<?xml version="1.0"?>
<record><wiki id="wiki?page_id=36">
	<page_name>about</page_name>
	<page_id>36</page_id>
	<page_title>about</page_title>
	<content>==About Xataface==

[[toc]]

Xataface is a flexible and shapable skin that sits on top of MySQL, making it accessible to every-day users. It automatically generates the appropriate forms, lists, and menus for a user to interact with the database without having to know any SQL. 

It is a full-featured Web application framework, and gives developers the flexibility to customize the features and behavior of their application via configuration files (using the simple INI-file syntax), templates, and plug-ins. A generic application with no customizations is completely functional, but the developer is free to customize things at his leisure.

===Who is Xataface for?===

Xataface is for web developers and database administrators who would like to build a front-end for their MySQL database.  However the resulting applications are targeted at non-technical users such as secretaries.

===Requirements===

====Xataface 1.1.x and below:====

* MySQL 3.23+
* PHP 4+

Some advanced features require MySQL version 4.1 or higher.

====Xataface 1.2 and higher====

* MySQL 3.23+
* PHP 5+

Some advanced features require MySQL version 5 or higher.

===At a Glance: Your first App===

# Create a directory for your app.
# Copy the &apos;&apos;xataface&apos;&apos; directory inside your application directory.
# Create a configuration file named &apos;&apos;conf.ini&apos;&apos; in your application directory with your database settings:&lt;code&gt;
[_database]
    host=localhost
    name=mydb
    user=me
    password=mypass

[_tables]
    ; A list of tables to include in your application&apos;s menu
    ; These tables must already exist in your database
    people=Profiles
    news=News Articles
&lt;/code&gt;
# Create an .htaccess file in your application directory to prevent access to your &apos;&apos;conf.ini&apos;&apos; file:&lt;code&gt;
&lt;FilesMatch &quot;\.ini$&quot;&gt;
Deny from all
&lt;/FilesMatch&gt;
&lt;/code&gt;
# Create a PHP script in your application directory as an access point for your app.  We&apos;ll call it &apos;&apos;index.php&apos;&apos;:&lt;code style=&quot;php&quot;&gt;
&lt;?php
// Include the Xataface API
require_once &apos;xataface/dataface-public-api.php&apos;;

// Initialize Xataface framework
df_init(__FILE__, &apos;xataface&apos;);
    // first parameter is always the same (path to the current script)
    // 2nd parameter is relative URL to xataface directory (used for CSS files and javascripts)

// Create a new application
$app =&amp; Dataface_Application::getInstance();

// Display the application
$app-&gt;display()
&lt;/code&gt;
# You&apos;re done.  Your app is ready to use!

This is just the beginning, though.  There is no limit to the customizations you can make on your application.

Read the [http://xataface.com/documentation/tutorial/getting_started Getting Started Tutorial] for more information on developing applications with Xataface.


===Product Comparison===

Xataface fits a niche that is not well covered by existing apps/frameworks.  Xataface is &apos;&apos;&apos;NOT&apos;&apos;&apos;:

* A database administration system like PHPMyAdmin
* Simply a software library/Framework like PHPCake
* Simply a content management system like Drupal
* A code generator

Xataface is a framework, but it is not a typical framework.  Most frameworks require a substantial amount of development before you get a usable application.  Xataface, on the other hand, provides you with a fully-functional application with as little as 4 lines of PHP code.  It doesn&apos;t generate any code so it is easy to maintain your application and expand on it later.

As a development framework, Xataface most closely resembles Django, a python framework for building data-driven applications.  As an application, Xataface most closely resembles Filemaker, a popular relational database that makes it easy for the end user to create layouts and manage their data.

===Features===

====General====

* &apos;&apos;&apos;Out-of-the-box Database Front-end&apos;&apos;&apos; - With as little as 4 lines of PHP code, you can have a full-featured web application for your database.
* &apos;&apos;&apos;Simple, Intuitive User interface&apos;&apos;&apos; - Default application is consistent and simple to use.  There is a &apos;tables&apos; menu, to select a table, and each table has &quot;details&quot;, &quot;list&quot;, and &quot;find&quot; tabs.  Very easy to navigate.
* &apos;&apos;&apos;Powerful configuration options&apos;&apos;&apos; - You can configure your application details (such as widget types) using simple configuration files.
* &apos;&apos;&apos;Extendible&apos;&apos;&apos; - You can modify your application as you see fit using configuration files and PHP delegate classes.
* &apos;&apos;&apos;Hooks&apos;&apos;&apos; - By observing simple conventions you can extend Xataface&apos;s functionality with hooks, triggers, and events.  E.g. add a function that is called after a record is inserted.
* &apos;&apos;&apos;Permissions&apos;&apos;&apos; - Powerful, pluggable permissions system.
* &apos;&apos;&apos;Authentication&apos;&apos;&apos; - Provides login/logout ability.  You just specify which table your users are stored in.
* &apos;&apos;&apos;Relationships&apos;&apos;&apos; - Tell Xataface how your tables are related to one another and it will provide you with more logical functionality for managing your data.
* &apos;&apos;&apos;Themeable&apos;&apos;&apos; - Xataface uses the Smarty template engine as a base, but extends it with some powerful new features such as extendable templates and theming support.
* &apos;&apos;&apos;Modular&apos;&apos;&apos; - There are several add-on modules available to extend the features of Xataface even further, and a simple API for writing your own modules.


====Editing====

* &apos;&apos;&apos;Automatic Form Generation&apos;&apos;&apos; - Automatically generates appropriate web forms to add new records and edit existing records.
* &apos;&apos;&apos;Widgets&apos;&apos;&apos; - Support for many different widget types including text fields, text areas, checkboxes, select lists, html editors, grids, file uploads, and more.
* &apos;&apos;&apos;Configurable&apos;&apos;&apos; - Customize forms using configuration files and delegate classes.
* &apos;&apos;&apos;Personalizable&apos;&apos;&apos; - Show different forms to different users depending on their permissions and preferences.
* &apos;&apos;&apos;Add Related Records&apos;&apos;&apos; - Insert records and automatically track their relationships to other tables.
* &apos;&apos;&apos;Editable Data Grid&apos;&apos;&apos; - Manage your data like a spreadsheet using the DataGrid module.
* &apos;&apos;&apos;Copy&apos;&apos;&apos; - Copy sets of records.
* &apos;&apos;&apos;Update Found Set&apos;&apos;&apos; - Update multiple records with one swipe.
* &apos;&apos;&apos;Fine-grained Permissions&apos;&apos;&apos; - Assign editing permission based on table, record, or field. 
* &apos;&apos;&apos;File uploads&apos;&apos;&apos; - Support for file uploads with storage either in a BLOB field or on the file system.
* &apos;&apos;&apos;Delete&apos;&apos;&apos; - Delete single record or delete the current found set.

====Searching====

* &apos;&apos;&apos;Automatic Find Form&apos;&apos;&apos; - The Xataface find form allows you to search a table on any field.
* &apos;&apos;&apos;Range Searches&apos;&apos;&apos; - Search for records matching values in a certain range (e.g. find all people between the ages of 20 and 30).
* &apos;&apos;&apos;Exact Matching&apos;&apos;&apos; - Search for exact matches.
* &apos;&apos;&apos;Partial Matching&apos;&apos;&apos; - Search for fields that contain a keyword phrase.
* &apos;&apos;&apos;Multi-field search&apos;&apos;&apos; - There is always a simple search field accessible which searches all fields in the current table.  E.g. a search for &quot;Tom&quot; would match any record in the current table that contained the phrase &quot;Tom&quot; in any of its columns.
* &apos;&apos;&apos;Related Record Searches&apos;&apos;&apos; - Find records that contain related records matching a search term.  (E.g. find all people who got an &apos;A&apos; in a particular course).


====Browsing====

* &apos;&apos;&apos;Automatic Details View&apos;&apos;&apos; - Each record has user-friendly details page to browse the contents of the record.
* &apos;&apos;&apos;AJAX Record Tree&apos;&apos;&apos; - Provides optional AJAX record tree to browse the data in your database by relationships.
* &apos;&apos;&apos;Expand for More&apos;&apos;&apos; - Quickly expand a row in list view to see the full record details.
* &apos;&apos;&apos;Drag and Drop Reordering&apos;&apos;&apos; - The details view for a record can be broken up into related sections.  Users can reorder these sections via drag and drop.

====Exporting====

* &apos;&apos;&apos;RSS&apos;&apos;&apos; - Support for RSS 1.0, 2.0 and Atom feeds of any found set.
* &apos;&apos;&apos;XML&apos;&apos;&apos; - Export any found set as XML so that the data can be interchanged with other products (e.g. desktop publishing suites).
* &apos;&apos;&apos;CSV&apos;&apos;&apos; - Export any found set to CSV (comma-separated-value) to open in a spreadsheet application like Excel.
* &apos;&apos;&apos;JSON&apos;&apos;&apos; - Export any found set to JSON.  This feature makes Xataface a good choice for serving the next generation of Web 2.0 AJAX applications.

====Internationalization====

* &apos;&apos;&apos;String Internationalization&apos;&apos;&apos; - Xataface fully supports internationalizing your application.  It provides you with language files to provide translations of all of the strings and labels in your application.
* &apos;&apos;&apos;Dynamic Data Translation&apos;&apos;&apos; - Xataface even allows you to internationalize your existing database data without having to change your database structure.
* &apos;&apos;&apos;Templates&apos;&apos;&apos; - Includes a {translate} tag for Smarty templates to easily translate template text.
* &apos;&apos;&apos;In the background&apos;&apos;&apos; - You can use Xataface to internationalize any PHP/MySQL website without having to make any drastic changes to your existing code.  Just include Xataface as a library and use some of its useful internationalization functions to convert your application into multiple languages.
* &apos;&apos;&apos;Translation Form&apos;&apos;&apos; - If multiple languages are enabled, Xataface provides a simple translation form to translate content between languages.
* &apos;&apos;&apos;Translation Status Tracking&apos;&apos;&apos; - Track the status of translations to mark whether they need to be retranslated.

====Importing====

* &apos;&apos;&apos;Import Filter API&apos;&apos;&apos; - Using delegate classes, it is easy to define an import filter to import any type of data into the database.
* &apos;&apos;&apos;User Preview&apos;&apos;&apos; - User can preview imported data before confirming that he wants to import it.

====History====

* &apos;&apos;&apos;Optional History Support&apos;&apos;&apos; - If history is enabled, all changes made to any data are recorded.
* &apos;&apos;&apos;Undo/Redo Support&apos;&apos;&apos; - Easily revert to an earlier version of a record.
* &apos;&apos;&apos;View Snapshot&apos;&apos;&apos; - Browse previous versions of records.
* &apos;&apos;&apos;View Diffs&apos;&apos;&apos; - View differences/changes between versions of records, similar to a wiki.

====Caching====

* &apos;&apos;&apos;Output cache&apos;&apos;&apos; - Supports output cache that caches output of pages to improve performance dramatically for busy sites.  Cache is automatically refreshed whenever changes are made to tables that are used to generate the page.
* &apos;&apos;&apos;APC Support&apos;&apos;&apos; - If APC (Alternate PHP Cache) is installed, Xataface will automatically use it to cache table configuration information.  This tends to increase performance by about 20%.


====Security====

* &apos;&apos;&apos;Fine-grained permissions&apos;&apos;&apos; - Define permissions to the entire application, a single table, by the record, or by the field.  Each feature has an associated permission that can be allowed or disallowed on a per-user basis.
* &apos;&apos;&apos;Cascading Permissions&apos;&apos;&apos; - You can very restrictive permissions to the application as a whole and then apply more permission permissions to specific tables or fields that you want uses to be able to access.  Table permissions override application permissions.  Field permissions override field permissions.
* &apos;&apos;&apos;Role-based permissions&apos;&apos;&apos; - You can define &quot;&quot;&quot;roles&quot;&quot;&quot; which are sets of permissions that can be assigned to users.
* &apos;&apos;&apos;Extendable Permissions Model&apos;&apos;&apos; - You can easily define your own permissions and roles, extending existing roles, custom for your application.
* &apos;&apos;&apos;Built-in Authentication&apos;&apos;&apos; - It is easy to set up login/logout features for your application.  Just tell Xataface which table you store your user records in, and Xataface will do the rest.
* &apos;&apos;&apos;Password Encryption&apos;&apos;&apos; - Xataface supports and is compatible with most of the standard password encryptions including MD5, SHA1, and MySQL Password.
* &apos;&apos;&apos;Pluggable Authentication&apos;&apos;&apos; - Easy to create your own authentication plugins in case you want to implement your own custom authentication.
* &apos;&apos;&apos;CAS&apos;&apos;&apos; - Module available for the Yale CAS (Central Authentication Service).
* &apos;&apos;&apos;LDAP&apos;&apos;&apos; - LDAP authentication module available.
* &apos;&apos;&apos;HTTP&apos;&apos;&apos; - Optional HTTP login support.  Standard login uses a web-based login form, but you can also use HTTP headers for authentication.

====Relationships====

* &apos;&apos;&apos;Powerful Relationship Model&apos;&apos;&apos; - It is easy to define relationships between your tables using simple configuration files.  Syntax is simple, but the results are powerful.
* &apos;&apos;&apos;Add New Related Record&apos;&apos;&apos; - Create a new record and add it to a parent record&apos;s relationship at the same time. (E.g. create a new &quot;course&quot; record and add it to a teacher&apos;s list of taught courses).
* &apos;&apos;&apos;Add Existing Related Record&apos;&apos;&apos; - Add an existing record to a parent record&apos;s relationship. (e.g. Add an existing course record to a teacher&apos;s list of taught courses).
* &apos;&apos;&apos;Remove related record&apos;&apos;&apos; - Remove a record from a relationship. (e.g. remove a course record from a teacher&apos;s list of taught courses).

====API====

Xataface includes a powerful API to allow you to more efficiently work with your database.

* &apos;&apos;&apos;Data Objects&apos;&apos;&apos; - Provides a simple API to work with database records.  Searching, loading, saving, editing, and deleting records supported.

====Templates====

* &apos;&apos;&apos;Smarty Template Engine&apos;&apos;&apos; - Xataface uses the Smarty template engine as a base, one of the fastest PHP template engines available.
* &apos;&apos;&apos;Template Inheritance&apos;&apos;&apos; - You can create templates that inherit from other templates, and replace the content in specified &quot;slots&quot; of the original template.  This drastically increases template reuse and development productivity.
* &apos;&apos;&apos;Cascading Support&apos;&apos;&apos; - All system templates are stored in the Dataface/templates directory.  Your application can have its own templates directory where you can place templates to override system templates.  All parts of the system can be overridden without modifying the original templates themselves.

====Themes====

Xataface includes a powerful themes API.  You can create multiple looks for your application and switch between them with a simple configuration setting.

====REST Support====

Xataface&apos;s intelligent URL protocols make it a powerful platform for REST web services.  You can specify a query directly in the URL to obtain the exact found-set that you want.  This is also very useful in standard web applications because you can easily create links to desired parts of your application.  Or you can use Xataface to provide missing functionality in your existing applications and link only to the parts of your Xataface app that you need.

===History===

Xataface (formerly Dataface) was originally created by Steve Hannah in 2005 to increase productivity created data-driven applications for Simon Fraser University.  He came from faculty that used Filemaker extensively for their databases.  As a PHP developer he preferred open technologies like MySQL as they provided fewer &quot;road blocks&quot;, but it was hard to deny the benefits of filemaker when it came to providing users with an instant user interface for their databases.  It was difficult to justify spending 3 weeks building an administration console for a MySQL application when it could have been done in 3 hours had Filemaker been used.

Xataface was designed to:

# Increase developer productivity to the point where MySQL applications could be created as quickly as Filemaker applications without sacrificing usability and functionality.
# Add an abstraction over a database to make is accessible to non-technical users.  The secretary shouldn&apos;t need to know SQL in order to interact with a database.
# Test the limits of PHP and MySQL

As it was built with the intention of providing an alternative for Filemaker, many implementation details and concepts have been inspired by Filemaker.  For example, Xataface&apos;s implementation of relationships is very similar to Filemaker relationships; as are valuelists.  In addition the method of searching follows many Filemaker conventions.

The first application built with Xataface was a group content management system for the Faculty of Applied Sciences at Simon Fraser University.  This system was used by faculty to manage their research profiles and their research groups.  The database itself pre-existed the Xataface implementation.   Xataface was used to build a new administrative interface to the system.  Since then Xataface has been used to develop many systems for SFU including website content management systems, auctions, event registration systems, research databases, shopping carts, and more.

==Where to go from here==

* [http://xataface.com/documentation/tutorial/getting_started Getting Started Tutorial]
* [http://xataface.com/videos Watch Demonstration Videos of Xataface]
* Sign up for the Xataface Maillist to receive free updates and development tips.  (See sign-up form in upper left of the page).</content>
	<keywords></keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=6">
	<page_name>actions.ini_file</page_name>
	<page_id>6</page_id>
	<page_title>actions.ini_file</page_title>
	<content>==actions.ini file Reference==

[[toc]]

The actions.ini file stores information about the various [[action]]s that can be performed by your application.  An action may be manifested in two ways:

# As a web page
# As a menu item

And there is no reason why an action cannot serve in both capacities simultaneously.  All menu items and functions that Xataface performs are defined in the Xataface actions.ini file (in the root of the Xataface installation dirctory).  You can also create an actions.ini file in your application&apos;s root directory to override existing Xataface actions, or to create your own.  If you want to modify an existing action instead of overriding it, you can use this syntax.

&lt;code&gt;
[browse &gt; browse]
	label = Browse
&lt;/code&gt;

The &amp;gt; symbol simply means to inherit from the existing browse action.  All the attributes are the same, and we just override the label to Browse (originally was Details)

Additionally, for actions that pertain only to a single table, an actions.ini file may be placed in any [[table configuration directory]].

===Syntax===

As with the [[fields.ini file]] and the [[valuelists.ini file]], the actions.ini file uses the simple [[INI file syntax]] to define its actions.  Each action is defined in its own section, and can have a number of directives to specify the action&apos;s behavior.

Here is a snippet from the Xataface actions.ini file to give you an idea:

&lt;code&gt;
;; Show the details of the current record
[browse]
	label = Details
	category = table_tabs
	url = &quot;{$this-&gt;url(&apos;-action=view&apos;)}&quot;
	accessKey = &quot;b&quot;
	mode = browse
	permission = view
	order=0

;; Show a list of the records in the current found set
[list]
	label = List
	category = table_tabs
	url = &quot;{$this-&gt;url(&apos;-action=list&apos;)}&quot;
	accessKey = &quot;l&quot;
	mode = list
	template = Dataface_List_View.html
	permission = list
	order=0.5

;; Show a &quot;Find Record Form&quot;
[find]
	label = Find
	category = table_tabs
	url = &quot;{$this-&gt;url(&apos;-action=find&apos;)}&quot;
	accessKey = &quot;f&quot;
	mode = find
	permission = find
	template = Dataface_Find_View.html
	order=0.75
&lt;/code&gt;

This snippet shows the definition of the browse, list, and find actions - three of the most central actions in a Xataface application.  Notice how each action has its own section (according to [[INI file syntax]]) with a number of directives which specify how the action behaves.  For instance, each action has a &quot;category&quot; value of &quot;table_tabs&quot;, which tells Xataface to display the actions as part of the table tabs in the user interface.

===Directives===

{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Version
|-
| [[action allow_override|allow_override]]
| An optional directive to indicate that this action can be overridden by more specific directives in another ini file.  Currently there is only support for a value of &quot;relationships.ini&quot; indicating that the settings can be overridden in the relationships.ini file.  In order for this to work, related=1 must also be set.
| 1.3rc4
|-
| [[action label|label]]
| The label to display if the action is used as a menu item.
| all
|-
| [[action category|category]]
| The name of the action&apos;s category which can be used to group this action together with other similar actions to be used in a menu in the user interface.
| all
|-
| [[action url|url]]
| If the action appears as a menu item, this is the URL that the menu item points to.  This may contain PHP expressions inside curly braces.
| all
|-
| [[action accessKey|accessKey]]
| The key code to automatically select this action if it is included as a menu item.  I.e. ALT+accessKey calls the action.
| all
|-
| [[action mode|mode]]
| This indicates which tab of the table tabs (find, details, list, etc...) that this action should appear to be part of when the action is viewed as a web page.  If this is left undefined, or it does not match any existing visible action in the table tabs, then no tab will appear to be selected.
| all
|-
| [[action permission|permission]]
| The name of a permission required to both see the action as part of a menu and to access the action as a web page.
| all
|-
| [[action visible|visible]]
| A boolean value indicating whether the action should be visible as a menu item.
| all
|-
| [[action condition|condition]]
| A boolean value or a PHP expression evaluating to a boolean value to indicate whether the action should be visible as a menu item.
| all
|-
| [[action url_condition|url_condition]]
| A PHP expression evaluating to a boolean value to indicate whether the URL directive should be evaluated.  This basically checks to make sure that its OK to evaluate the &quot;url&quot; expression, just in case the current state of affairs would cause it to throw a fatal error.
| all
|-
| [[action order|order]]
| A numeric value indicating the order in which the action should be displayed as part of a menu.  Low numbers result in higher placement in the menu.
| all
|-
| [[action icon|icon]]
| The path to an icon that should be used when the action appears as a menu item.
| all
|-
| [[action template|template]]
| The path to the template that should be used when the action is displayed as a web page.
| all
|-
| [[action description|description]]
| Mouseover text for the action (when displayed as a menu item).
| all
|}

===PHP Expression Context===

Notice that the [[action url|url]], [[action condition|condition]], and [[action url_condition|url_condition]] directives allow you to use a PHP expression for their values.  In order for this to be helpful, you should know a little bit about the context and environment in which these expressions will be executed.  All expressions are evaluated immediately prior to being rendered, so the same action can be displayed multiple times in the same page, but have very different resulting values for their [[action url|urls]] and [[action condition|conditions]].

These expressions are all executed within the context of the Dataface_Application::parseString() method, with the following variables loaded in the local symbol table (i.e. you can use the following variables in your expressions).

{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Version
|-
| [[action context:site_url|$site_url]]
| The URL to the current application&apos;s directory (not including &quot;index.php&quot;)
| all
|-
| $site_href
| The URL to the current application including &quot;index.php&quot;
| all
|-
| $dataface_url
| The URL to the xataface installation directory.
| all
|-
| $table
| The name of the current table (i.e. the value of the &quot;-table&quot; request parameter&quot;
| all
|-
| $query
| An associative array of the current query variables.
| all
|-
| $app
| A reference to the current Dataface_Application object.  Alias of &quot;$this&quot;
| all
|-
| $resultSet
| A reference to the Dataface_QueryTool object for the current query.
| all
|-
| [[action context:record|$record]]
| A reference to the current Dataface_Record object.
| all
|-
| [[action context:context|$context]]
| An associative array of context variables that are passed to the action from the context in which the action is called.
| all
|}</content>
	<keywords></keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=183">
	<page_name>advmultiselect</page_name>
	<page_id>183</page_id>
	<page_title></page_title>
	<content></content>
	<keywords></keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=123">
	<page_name>afterCopy</page_name>
	<page_id>123</page_id>
	<page_title>afterCopy Delegate class Method</page_title>
	<content>Return to [[Delegate class methods]]

[[toc]]

===Synopsis===

A delegate class method that will be executed after a record is copied using the copy set or copy selected function.  All xataface copies are shallow which means that related records are not copied by default.  If you want a more complex copy function for a table you can implement functionality in this hook.

Available since version 1.3

===Signature===
&lt;code&gt;
function afterCopy( Dataface_Record $original, Dataface_Record $copy);
&lt;/code&gt;

===Parameters===

* &apos;&apos;&apos;$original&apos;&apos;&apos; - The original record that was copied.
* &apos;&apos;&apos;$copy&apos;&apos;&apos; - The resulting copied record.

===Returns===

* Either return nothing or you may return a PEAR_Error object to indicate that an error occurred with the copy.

==See Also==

* [[beforeCopy]] - The beforeCopy hook that can be implemented in the delegate class to run just before a record is copied.
</content>
	<keywords>afterCopy, copy record hook</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=14">
	<page_name>afterRegister</page_name>
	<page_id>14</page_id>
	<page_title>afterRegister</page_title>
	<content>==afterRegister() Trigger==

A trigger that can be implemented in the [[Application Delegate Class]] or the [[Table Delegate Class]], to be executed after the registration form is saved.  This can be used to perform some custom actions like emailing the administrator.

===Signature===

function afterRegister( Dataface_Record &amp;$record ) : mixed

====Parameters====

{| class=&quot;listing listing2&quot;
! Name
! Description
|-
| &amp;$record
| A Dataface_Record object encapsulating the record that is being inserted in the users table for this registration.
|-
| returns
| Mixed. If this method returns a PEAR_Error object, then registration will fail with an error.
|}

===Example===

&lt;code&gt;
&lt;?php
class conf_ApplicationDelegate {
    function afterRegister(&amp;$record){
        // mail the admin to let him know that the registration is occurring.
        mail(&apos;admin@example.com&apos;, &apos;New registration&apos;, &apos;A new user &apos;.$record-&gt;val(&apos;username&apos;).&apos; has registered);
    }
}
&lt;/code&gt;

===See Also===

* [[beforeRegister]]
* [[validateRegistrationForm]]
* [[sendRegistrationActivationEmail]]
* [[getRegistrationActivationEmailInfo]]
* [[getRegistrationActivationEmailSubject]]
* [[getRegistrationActivationEmailMessage]]
* [[getRegistrationActivationEmailParameters]]
* [[getRegistrationActivationEmailHeaders]]</content>
	<keywords></keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=181">
	<page_name>after_action_activate</page_name>
	<page_id>181</page_id>
	<page_title>after_action_activate Delegate Class Method</page_title>
	<content>Return to [[Application Delegate Class]]

[[toc]]


The &apos;&apos;&apos;after_action_activate&apos;&apos;&apos; hook is a method that can be defined in the [[Application Delegate Class]] which is called after an account has been activated via the registration process.  The full registration process goes as follows:

# User fills in registration form.
# An email is sent to the user with a link to activate their account.
# User clicks on activation link.
# User is taken back to the application and activation occurs, which consists of creating a new record in the &apos;&apos;&apos;users&apos;&apos;&apos; table.
# The &apos;&apos;after_action_activate&apos;&apos; trigger is called.

===Since===

This hook has been available since Xataface Version 1.2

===Example===

&lt;code&gt;
/**
 * A trigger to send the user a confirmation email after their account has been activated.
 * @params array $params Associative array of passed parameters.  Contains a single key &apos;record&apos;
 * with the Dataface_Record object of the users table with the user that was activated.
 */
function after_action_activate(array $params){
    $user = $params[&apos;record&apos;];
    
    mail($user-&gt;val(&apos;email&apos;), &apos;Your account is activated&apos;, &apos;Your account has been activated... etc..&apos;);
}
&lt;/code&gt;

===See Also===

* [[Application Delegate Class]]
* [[registration_form]] - More information user registration forms.
* [[beforeRegister]] - Trigger called before the user registration form is saved.
* [[afterRegister]] - Trigger called after registration form is saved.
* [[validateRegistrationForm]] - Validates the input into the registration form.
* [[sendRegistrationActivationEmail]] - Overrides the sending of the registration activation email.
* [[getRegistrationActivationEmailInfo]] - Overrides the activation email info.  Returns an associative array of the email details (e.g. subject, to, headers, etc...
* [[getRegistrationActivationEmailSubject]] - Returns the subject of the activation email.
* [[getRegistrationActivationEmailMessage]] - Returns the message body for the activation email.
* [[getRegistrationActivationEmailParameters]] - Returns the parameters for the actication email.
* [[getRegistrationActivationEmailHeaders]] - Returns the headers for the activation email.
</content>
	<keywords>Registration, activation, register, activate, users</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=33">
	<page_name>after_action_new</page_name>
	<page_id>33</page_id>
	<page_title>after_action_new</page_title>
	<content>==after_action_new trigger==

[[toc]]

This trigger is called after the &apos;&apos;&apos;new&apos;&apos;&apos; action is successfully completed.  This trigger can be defined in the table [[Delegate class methods|delegate class]] and is often used to redirect to a particular page after a new record is submitted.  This should not be confused with the [[afterInsert]] trigger, which is executed after a record is inserted into the database (this can occur multiple times per request).  The after_action_new trigger is only executed once after the &apos;new&apos; action has been successfully completed.  i.e. a maximum of once per request.

===Signature===

&lt;code&gt;
function after_action_new($params=array()){ ... } : return void
&lt;/code&gt;

====Parameters====

This method takes a single associative array as a parameter. This array includes the following keys:

* &apos;&apos;&apos;record&apos;&apos;&apos; - The [http://dataface.weblite.ca/Dataface_Record Dataface_Record] object that was just inserted.


===Examples===

====Example 1: Redirect to the view tab for the inserted record====

&lt;code&gt;
function after_action_new($params=array()){
    $record =&amp; $params[&apos;record&apos;];
    header(&apos;Location: &apos;.$record-&gt;getURL(&apos;-action=view&apos;).&apos;&amp;--msg=&apos;.urlencode(&apos;Record successfully inserted.&apos;));
    exit;
}
&lt;/code&gt;
</content>
	<keywords></keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=12">
	<page_name>Application_Delegate_Class</page_name>
	<page_id>12</page_id>
	<page_title>Application Delegate Class</page_title>
	<content>[[toc]]

===Synopsis===

The application delegate class is similar to the [[Delegate_class_methods|table_delegate_class]] except that it is applicable to the application as a whole, not just one table.  It allows the developer to implement hooks that will be executed by Xataface to modify behavior.

Examples of customizations that can be made with the Application Delegate class include:

* Permissions
* User Preferences
* Custom content to be inserted into templates.
* Triggers
* more.

===Location===

The delegate class is optional and should be located in the conf/ApplicationDelegate.php file in the application directory.

===Example===

&lt;code&gt;
&lt;?php
class conf_ApplicationDelegate {
   function getPermissions(&amp;$record){
       return Dataface_PermissionsTool::NO_ACCESS();
   }
}
&lt;/code&gt;

===Available Methods===

====Triggers====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| after_action_activate
| Trigger called after activation is complete.  Activation occurs after a user registers and responds to the registration confirmation email.
| 1.2.5
|-
| after_action_login
| Trigger called after a user logs in
| 1.0
|-
| after_action_logout
| Trigger called after a user logs out
| 1.0
|-
| after_action_edit
| Trigger called after the edit action completes.
| 1.0
|-
| after_action_new
| Trigger called after new action completes.
| 1.0
|-
| after_action_delete
| Trigger called after the delete action completes.
| 1.0
|-
| [[after_action_activate]]
| Trigger called after successfully email validation (after registering).
| 1.2
|-
| [[before_authenticate]]
| Trigger called just before authentication is carried out.  This allows you to change the authentication type based on such things as SESSION variables etc...
| 1.2.5
|-
| [[beforeHandleRequest]]
| Trigger called on each page request immediately before the action handler is called.  This is handy if you need to perform some action on each page request, such as changing the default action depending on the logged in user.
| 1.0
|-
| [[loginFailed]]
| Trigger called after a failed login attempt.  Allows you to provide your own logging.
| 2.0.1
|-
| [[startSession]]
| If implemented, this overrides how Xataface starts its sessions.  If you implement this method, your custom method should at least include a call to [http://php.net/session_start session_start].
| 1.2.5
|}

====Preferences====

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| getPreferences
| Returns the user preference settings.
| 0.6
|}


====Permissions====

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| getPermissions
| Returns the permissions available for a given record.
| 0.6
|-
| getRoles
| Returns the roles allowed for a given record.
| 1.0
|-
| __field__permissions
| Returns the default permissions for a field of a given record.
| 1.0
|-
| __field__roles
| Returns the default roles for a field of a given record.
| 1.0
|-
| fieldname__permissions
| Returns the permissions that are allowed for the field &quot;fieldname&quot; on a given record.
| 0.7
|-
| fieldname__roles
| Returns the roles that are allowed for the field &quot;fieldname&quot; on a given record.
| 1.0
|-
| rel_relationshipname__permissions
| Returns the permissions pertaining to the relationship &apos;&apos;relationshipname&apos;&apos; on a given record.
| 1.0
|-
| rel_relationshiopname__roles
| Returns the role or roles pertaining to the relationship &apos;&apos;relationshipname&apos;&apos; on a given record.
| 1.0
|}

See [[permissions]] for more information about Xataface&apos;s permissions architecture and how to implement custom application permissions.

&lt;nowiki&gt;&lt;a name=&quot;registration&quot;&gt;&lt;/a&gt;&lt;/nowiki&gt;
====Registration====

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[beforeRegister]]
| Trigger called before the user registration form is saved.
| 1.0
|-
| [[afterRegister]]
| Trigger called after registration form is saved.
| 1.0
|-
| [[validateRegistrationForm]]
| Validates the input into the registration form.
| 1.0
|-
| [[sendRegistrationActivationEmail]]
| Overrides the sending of the registration activation email.
| 1.0
|-
| [[getRegistrationActivationEmailInfo]]
| Overrides the activation email info.  Returns an associative array of the email details (e.g. subject, to, headers, etc...
| 1.0
|-
| [[getRegistrationActivationEmailSubject]]
| Returns the subject of the activation email.
| 1.0
|-
| [[getRegistrationActivationEmailMessage]]
| Returns the message body for the activation email.
| 1.0
|-
| [[getRegistrationActivationEmailParameters]]
| Returns the parameters for the actication email.
| 1.0
|-
| [[getRegistrationActivationEmailHeaders]]
| Returns the headers for the activation email.
| 1.0
|-
| [[after_action_activate]]
| Trigger fired after activation is complete.
| 1.2
|}

See [[registration form]] for more information about Xataface&apos;s registration system and how to allow users to register for an account on your application.

&lt;nowiki&gt;&lt;a name=&quot;password-reset&quot;&gt;&lt;/a&gt;&lt;/nowiki&gt;
====Forgot Password====

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[getPasswordChangedEmailInfo]]
| Optional method to define the settings for the email that is sent to the user upon successful resetting of their password using the password reset function.  
| 1.3
|-
| [[getResetPasswordEmailInfo]]
| Optional method to define the settings for the email that is sent when a user requests to reset their password.  This step comes before the password changed email as first the user requests a password reset and receives this email.  Then they click a link in this email to reset the password upon which time they receive a second email containing their temporary password.  That email is generated by the [[getPasswordChangedEmailInfo]] method if defined.  If this method is not defined then a generic email predefined in Xataface will be sent instead.
| 1.3
|}




====RSS Feed Customization====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[getFeedItem]]
| For RSS Feeds, overrides the defaults and returns an associative array with feed elements for a particular record
| 1.0
|-
| [[getFeed]]
| For RSS feeds, overrides the default feed for a query, returning an array of feed items.
| 1.0
|-
| getFeedSource
| Overrides the default feed source parameter for an RSS feed.
| 1.0
|-
| [[getRelatedFeed]]
| For RSS feeds, overrides the default feed for a related feed.
| 1.0
|-
| getRSSDescription
| Overrides the default generated RSS description for a record.
| 1.0
|}


====Template Customization====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[block__blockname]]
| Outputs content that is meant to override a slot or a block named &quot;blockname&quot;.
| 0.6
|-
| [[getNavItem]]
| Overrides the navigation menu item for a particular table.
| 1.3
|-
| [[navItemIsSelected]]
| Overrides the &quot;selected&quot; setting for nav menu items.  This is used by the default implementation of [[getNavItem]].
| 1.3
|-
| [[getTemplateContext]]
| Returns an associative array of variables that should be made available to all templates.
| 1.0
|}

====Output Cache Customization====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[getOutputCacheUserId]]
| Returns a unique user id that is used by the output cache to ensure that different users don&apos;t use the same cached page (unless appropriate).   This is generally not necessary as the output cache by default uses a different cache for each user... but in some cases you may want to use a different cache for the same user.
| 2.0
|}

====Valuelist Customization====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[valuelist__valuelistname]]
| Defines a valuelist named &apos;&apos;valuelistname&apos;&apos;.
| 0.7
|}
</content>
	<keywords>application delegate class</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=93">
	<page_name>Authenticating_Against_the_Joomla!_Users_Table</page_name>
	<page_id>93</page_id>
	<page_title></page_title>
	<content>Xataface is able to use the joomla users table to authenticate against so that, you can allow your users to log into your Xataface application using the same credentials as they use to access your joomla website. Achieving this level of integration requires 2 simple steps :
1 - Set up the [_auth] section of your conf.ini file to reference the joomla users table and the correct username and password columns.
2 - Create a delegate class for the joomla users table to be able to decrypt the password set in the table.
==Configure the conf.ini file==
Joomla users table is named jos_users. So you have to declare this table in the conf.ini file.
&lt;code&gt;[_auth]
users_table = jos_users
username_column = username
password_column = password&lt;/code&gt;
Note that username_column and password_column are very simple...
==Create a delegate class for your users table==
Now we have to create a delegate class for the users table to decrypt the passwords set in joomla.
Joomla uses a custom md5 encryption.
===Joomla encryption===
When a user is setting a password in joomla, the system does several things :
1 - generate a random key containing alphanumeric characters
example : 
&lt;code&gt;8NdiRqLRKLHaNwudJ3InJknsew9sc7pL&lt;/code&gt;
2 - concate the clear entered password with the random key
example : 
&lt;code&gt;password8NdiRqLRKLHaNwudJ3InJknsew9sc7pL&lt;/code&gt;
3 - doing a md5 encryption on the result string
example : 
&lt;code&gt;md5(password8NdiRqLRKLHaNwudJ3InJknsew9sc7pL = f2b1fb3996442db549c1ed1a1eebbfe1&lt;/code&gt;
4 - concate the md5 string with the random key separated by &quot;:&quot;
example :
&lt;code&gt;f2b1fb3996442db549c1ed1a1eebbfe1:8NdiRqLRKLHaNwudJ3InJknsew9sc7pL&lt;/code&gt;
So it&apos;s a great encryption but xataface doesn&apos;t know how to do that.
Here is the utility of the delegate class. We will define a function inside which could compare the entered password in xataface with the joomla stored password.
===Creating the delegate class===
1 - Add a jos_users directory in your directory table
2 - Create a jos_users.php file inside this new directory
===Creating the decrypt password function===
Before posting this code, I would like to thank fantomasdm who created this function.
So here is the code of the function to paste directly in the jos_users delegate class :
&lt;code&gt;&lt;?
class tables_jos_users {
	
function password__serialize($password){

   $app =&amp; Dataface_Application::getInstance(); 
   $query = &quot;SELECT id, gid, block, password, usertype FROM jos_users where username=&apos;&quot;.$_POST[&apos;UserName&apos;].&quot;&apos;&quot;;
   $result = mysql_query($query,$app-&gt;db()) or die(&quot;Query failed&quot; . mysql_error() );

   $line = mysql_fetch_array($result, MYSQL_ASSOC);
   mysql_free_result($result);

   $arraypass=explode(&quot;:&quot;, $linea[&apos;password&apos;]);
   $key=$arraypass[1];
   
   $ret = md5(trim($password).$key).&quot;:&quot;.$key;
   return $ret;
} 
}
?&gt;&lt;/code&gt;
Save your file and test the result.
Enjoy ! ;-)</content>
	<keywords>joomla authentication md5</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=92">
	<page_name>Authenticating_Against_the_PHPBB_Users_table</page_name>
	<page_id>92</page_id>
	<page_title>Authenticating Against the PHPBB Users Table</page_title>
	<content>Return to [[authentication]]

[[toc]]

Xataface is able to use the PHPBB users table to authenticate against so that, you can allow your users to log into your Xataface application using the same credentials as they use to access your PHPBB message forum.  Achieving this level of integration requires 2 simple steps:

# Set up the [[_auth]] section of your [[conf.ini file]] to reference the PHPBB users table and the correct username and password columns.
# Specify the correct encryption on the password column.  This step will be different for different versions of PHPBB.

==PHPBB 2==

PHPBB version 2 and lower simply use MD5 encryption on the password column, which Xataface supports natively via the [[encryption]] directive of the [[fields.ini file]].  Therefore we can set up our Xataface application to authenticate against our PHPBB2 database (&apos;&apos;&apos;assuming that our PHPBB is set up in the same database as our Xataface app&apos;&apos;&apos;) by doing the following:

# Set up the [_auth] section of the [[conf.ini file]] as follows:&lt;code&gt;
[_auth]
users_table = phpbb_users
username_column = username
password_column = user_password
&lt;/code&gt;
# Set up the user_password field to use md5 encryption in the &apos;&apos;tables/phpbb_users/fields.ini&apos;&apos; file &lt;code&gt;
[user_password]
encryption=md5
&lt;/code&gt;

That&apos;s it!  Now you should be able to log into your Xataface application using the username/password from PHPBB.


==PHPBB 3==

PHPBB version 3 and higher uses a custom encryption function for the password column so it is a little more complicated (but not that much).  Step one (the [[conf.ini file]]) is the same as for PHPBB version 2 listed above.  The 2nd part, however, requires us to implement a custom serialization for the user_password field.  So the steps are below:

# Set up the [_auth] section of the [[conf.ini file]] as follows:&lt;code&gt;
[_auth]
users_table = phpbb_users
username_column = username
password_column = user_password
&lt;/code&gt;
# Implement the user_password__serialize() method in your phpbb_users delegate class (i.e. the &apos;&apos;tables/phpbb_users/phpbb_users.php&apos;&apos; file):&lt;code&gt;
&lt;?php
class tables_phpbb_users {
	

	function user_password__serialize($password){
		$itoa64 = &apos;./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz&apos;;
		$sql = &quot;select user_password from phpbb_users where username=&apos;&quot;.addslashes($_POST[&apos;UserName&apos;]).&quot;&apos;&quot;;
		$res = mysql_query($sql, df_db());
		if ( !$res ) throw new Exception(mysql_error(df_db()));
		$row = mysql_fetch_assoc($res);
		mysql_free_result($res);
		$hash = $this-&gt;_hash_crypt_private($password, $row[&apos;user_password&apos;], $itoa64);
		return $hash;
	}
	
	
	/**
	* The crypt function/replacement
	*/
	function _hash_crypt_private($password, $setting, &amp;$itoa64)
	{
		$output = &apos;*&apos;;
	
		// Check for correct hash
		if (substr($setting, 0, 3) != &apos;$H$&apos;)
		{
			return $output;
		}
	
		$count_log2 = strpos($itoa64, $setting[3]);
	
		if ($count_log2 &lt; 7 || $count_log2 &gt; 30)
		{
			return $output;
		}
	
		$count = 1 &lt;&lt; $count_log2;
		$salt = substr($setting, 4, 8);
	
		if (strlen($salt) != 8)
		{
			return $output;
		}
	
		/**
		* We&apos;re kind of forced to use MD5 here since it&apos;s the only
		* cryptographic primitive available in all versions of PHP
		* currently in use.  To implement our own low-level crypto
		* in PHP would result in much worse performance and
		* consequently in lower iteration counts and hashes that are
		* quicker to crack (by non-PHP code).
		*/
		if (PHP_VERSION &gt;= 5)
		{
			$hash = md5($salt . $password, true);
			do
			{
				$hash = md5($hash . $password, true);
			}
			while (--$count);
		}
		else
		{
			$hash = pack(&apos;H*&apos;, md5($salt . $password));
			do
			{
				$hash = pack(&apos;H*&apos;, md5($hash . $password));
			}
			while (--$count);
		}
	
		$output = substr($setting, 0, 12);
		$output .= $this-&gt;_hash_encode64($hash, 16, $itoa64);
	
		return $output;
	}
	
	/**
	* Encode hash
	*/
	function _hash_encode64($input, $count, &amp;$itoa64)
	{
		$output = &apos;&apos;;
		$i = 0;
	
		do
		{
			$value = ord($input[$i++]);
			$output .= $itoa64[$value &amp; 0x3f];
	
			if ($i &lt; $count)
			{
				$value |= ord($input[$i]) &lt;&lt; 8;
			}
	
			$output .= $itoa64[($value &gt;&gt; 6) &amp; 0x3f];
	
			if ($i++ &gt;= $count)
			{
				break;
			}
	
			if ($i &lt; $count)
			{
				$value |= ord($input[$i]) &lt;&lt; 16;
			}
	
			$output .= $itoa64[($value &gt;&gt; 12) &amp; 0x3f];
	
			if ($i++ &gt;= $count)
			{
				break;
			}
	
			$output .= $itoa64[($value &gt;&gt; 18) &amp; 0x3f];
		}
		while ($i &lt; $count);
	
		return $output;
	}

	

}
&lt;/code&gt;</content>
	<keywords>PHPBB, authentication, security, authentication modules</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=21">
	<page_name>authentication</page_name>
	<page_id>21</page_id>
	<page_title>authentication</page_title>
	<content>==Xataface Authentication==

[[toc]]

Xataface comes with authentication ready to roll out of the box.  With a couple of [[_auth|configuration options]] in the [[conf.ini file]], you can activate the default authentication scheme which uses a table (of your choice) in the database to authenticate against.  It supports [[password encryption]], and even includes a [[registration form]] if you choose to allow registrations for your application.

In addition Xataface&apos;s authentication is pluggable, meaning you can write your own plug-ins to integrate your application with any authentication scheme you choose.  Some authentication modules that already exist include:

* [[CAS Authentication Module|Yale CAS]]
* [[LDAP_or_Active_Directory|LDAP]]
* [[Facebook Authentication Module|Facebook]]
* [[HTTP Authentication Module|HTTP]]

====See Also:====

* [[Writing Custom Authentication Plugins]]
* [[Authenticating Against the PHPBB Users table]]
* [[Authenticating Against the Joomla! Users Table]]

Depending on the complexity of the authentication scheme, these plugins may be easy or complex to create.

===Setting up Basic Authentication===

# Create a table (if you haven&apos;t already) to store your application&apos;s users.  At the bare minimum, this table should have fields to store the username and password (you may call these fields whatever you like).  An example table might be: &lt;code&gt;
CREATE TABLE `users` (
  `username` VARCHAR(32) NOT NULL,
  `password` VARCHAR(32) NOT NULL,
  PRIMARY KEY (`username`)
)
&lt;/code&gt;
# Add the following ([[_auth|_auth section]]) to your [[conf.ini file]]: &lt;code&gt;
[_auth]
     users_table=users
     username_column=username
     password_column=password
&lt;/code&gt;  This tell Xataface which table you are storing your user accounts in, and the names of the username and password columns.
# Add a sample user record to the users table if one does not exist yet.&lt;code&gt;
INSERT INTO `users` (`username`,`password`) VALUES (&apos;steve&apos;,&apos;mypass&apos;)
&lt;/code&gt;
# Load your application in your web browser and you&apos;ll notice a &quot;login&quot; link in the upper right that allows you to log in.


===Using MD5 Encryption for the Password===

It is good practice to perform some type of encryption on passwords that you store in a database, so that they will be safe, even if your server&apos;s security is compromised.  One common form of encryption it MD5.  You can apply encryption to your passwords by defining the &apos;&apos;&apos;encryption&apos;&apos;&apos; property to the &apos;&apos;&apos;[password]&apos;&apos;&apos; field&apos;s section of the users table [fields.ini file]. E.g.
&lt;code&gt;
[password]
    encryption=md5
&lt;/code&gt;

This tells Xataface to save data to the password field of the users table with MD5 encryption.

In order to switch to MD5 encryption with an existing Xataface installation, all un-encrypted (plain text) passwords must be first converted to MD5. There are several ways to do this. One method is to directly convert the passwords in the database with the MySQL MD5 function. This can be done from the command-line or using a tool such as phpMyAdmin. It can also be done solely within Xataface as follows, assuming a small number of users where you either know all of the passwords or are planning to change them:

# Log in to your Xataface application as an existing user with ADMIN-level access.
# Navigate to the users table. If you do not already have a link to it, modify your URL to include &quot;-table=&quot; and the name of your users table.
# While logged in, add the encryption=md5 parameter to the fields.ini file as described above.
# Select each user and re-enter or reset their password. It will now be stored with MD5 encryption.
# After completing the above step for all users, you may log out and log back in to verify the change.

===Limiting Access Based on User===

Authentication and permissions are distinct issues, but they are related.  It is quite common to require a user to log in to access a section of an application.  Permissions can be defined in either the Application delegate class or a table&apos;s delegate class - or both.

As an example, if we want to require users to log in to access our application we could define the following getPermissions() method to our application delegate class:

&lt;code&gt;
&lt;?php
class conf_ApplicationDelegate {
    function getPermissions(&amp;$record){
        // $record is a Dataface_Record object
        $auth =&amp; Dataface_AuthenticationTool::getInstance();
        $user =&amp; $auth-&gt;getLoggedInUser();
        if ( $user ) return Dataface_PermissionsTool::ALL();
        else return Dataface_PermissionsTool::NO_ACCESS();
    }
}
&lt;/code&gt;


===Checking Who Is Logged In===

The [http://dataface.weblite.ca/Dataface_AuthenticationTool Dataface_AuthenticationTool] class handles all of the dirty work of Xataface&apos;s authentication.  It provides public methods to check who is logged in and perform authentication if necessary.  Anywhere inside your Xataface application you can find out who is logged in using one of the following two methods:

* [http://dataface.weblite.ca/getLoggedInUser getLoggedInUser()] - Returns a [http://dataface.weblite.ca/Dataface_Record Dataface_Record] object representing a record from the users table.
* [http://dataface.weblite.ca/getLoggedInUsername getLoggedInUsername()] - Returns a string.

It is quite useful in the getPermissions() method of your delegate classes to find out who is logged in:

&lt;code&gt;
function getPermissions(&amp;$record){
    $auth =&amp; Dataface_AuthenticationTool::getInstance();
    $user =&amp; $auth-&gt;getLoggedInUser();
    if ( $user and $user-&gt;val(&apos;username&apos;) == &apos;shannah&apos; ){
        // Steve is logged in so we give him special permissions
        return Dataface_PermissionsTool::ALL();
    } else {
        // Steve is not logged in so we give only read only permissions
        return Dataface_PermissionsTool::READ_ONLY();
    }
}
&lt;/code&gt;

====Checking Who is Logged In from a Template====

All templates in Xataface have access to the *$ENV* array that contains references to lots of useful information, including the currently logged in user:

* &apos;&apos;&apos;$ENV.user&apos;&apos;&apos; - The user object of the currently logged in user (or null if nobody is logged in).  This is a [http://dataface.weblite.ca/Dataface_Record Dataface_Record] object.
* &apos;&apos;&apos;$ENV.username&apos;&apos;&apos; - The name of the currently logged in user.  A string.

For example:

&lt;code&gt;
&lt;!-- 
     Print &apos;Hello Steve&apos; if Steve is logged in,
     &apos;Hello Helen&apos; if Helen is logged in, or just 
     &apos;Hello&apos; if nobody is logged in. 
--&gt;
Hello {$ENV.username}

&lt;!-- Print some personal user info --&gt;
{if $ENV.user}
    Phone number: {$ENV.user-&gt;val(&apos;phone&apos;)}&lt;br/&gt;
    Email address: {$ENV.user-&gt;val(&apos;email&apos;)}&lt;br/&gt;
{/if}
&lt;/code&gt;
This example presumes that the users table has &apos;phone&apos; and &apos;email&apos; fields.


====See Also:====

* [http://xataface.com/documentation/tutorial/getting_started/permissions Permissions Section of Getting Started Tutorial]
* [http://xataface.com/documentation/how-to/disallow_tables How to disallow access to tables in conf.ini file]
* [http://xataface.com/documentation/how-to/security_filters How to use security filters to hide records from certain users]
* [[LDAP_or_Active_Directory| Using LDAP or Active Directory for Authentication]]
* [[_auth|_auth section directives in conf.ini file]]</content>
	<keywords>authentication, [_auth], CAS Authentication, Authentication Modules, Basic Authentication, Security</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=108">
	<page_name>beforeAddRelatedRecord</page_name>
	<page_id>108</page_id>
	<page_title>beforeAddRelatedRecord Delegate Class Method</page_title>
	<content>Return to [[Delegate class methods]]

[[toc]]

==Synopsis==

The &apos;&apos;beforeAddRelatedRecord&apos;&apos; delegate class method can be implemented in any table&apos;s delegate class.  It will be executed before any related record is added to that table&apos;s relationships.  Since it will be fired for all relationships on the table, you will have to include logic to only execute if the relationship that you are targeting is being added to.

==Method Signature==

&lt;code&gt;
function beforeAddRelatedRecord( Dataface_RelatedRecord $record );
&lt;/code&gt;

==Parameters==

* &apos;&apos;&apos;$record&apos;&apos;&apos; - The [http://dataface.weblite.ca/Dataface_RelatedRecord Dataface_RelatedRecord] object encapsulating the record that is being added to the relationship.

===Returns===

* void - If all is well
* [http://dataface.weblite.ca/Dataface_Error Dataface_Error] object if something went wrong.  

It is quite common to return a permission denied error from this method after doing some checks. e.g.

&lt;code&gt;
function beforeAddRelatedRecord($record){
    if ( /* some checks here */ ){
        return Dataface_Error::permissionDenied(&apos;Sorry you don\&apos;t have permission to do this.&apos;);
    }
}
&lt;/code&gt;

==Examples==

===Example 1: Permission Check===

&lt;code&gt;
function beforeAddRelatedRecord($record){
    if ( $record-&gt;_relationshipName == &apos;program_roles&apos; ){
        // check to make sure that we are allowed to add roles to this program
        $program = df_get_record(&apos;programs&apos;, array(&apos;program_id&apos;=&gt;&apos;=&apos;.$record-&gt;val(&apos;program_id&apos;)));
        if ( !$program ){
            return Dataface_Error::permissionDenied(&quot;Program could not be found&quot;);
        }
        if ( !$program-&gt;checkPermission(&apos;add new related record&apos;, array(
                &apos;relationship&apos; =&gt; &apos;program_roles&apos;
                )
             )
           ){
            return Dataface_Error::permissionDenied(&quot;You don&apos;t have permission to add roles to this program&quot;);
        }
    }
}
&lt;/code&gt;

The above example requires a little bit of context to understand.  This method is defined in the &apos;users&apos; table.  There is a relationship between the &apos;&apos;users&apos;&apos; table and the &apos;&apos;programs&apos;&apos; table called &apos;program_roles&apos;.  It keeps track of the roles that users have with respect to programs.  There is a mirror relationshp in the &apos;&apos;programs&apos;&apos; table that goes to the &apos;&apos;users&apos;&apos; table, also named &apos;&apos;program_roles&apos;&apos;.  Both the &apos;&apos;users&apos;&apos; table and the &apos;&apos;programs&apos;&apos; table contain rel_program_roles__roles() methods to define who can and cannot add to this relationship.  However these don&apos;t discern on the content that is being added to the relationship, so it is still possible that an ineligible program could be added to the relationship via the users table (or vice versa).

So, in the &apos;&apos;users&apos;&apos; table we defined the &apos;&apos;beforeAddRelatedRecord&apos;&apos; above which checks the permissions of the programs table to see if that particular program can be added to this relationship by this user.


==See Also==

* [http://dataface.weblite.ca/Dataface_RelatedRecord Dataface_RelatedRecord API Docs]
* [[Delegate class methods]]
* [http://xataface.com/documentation/tutorial/getting_started/relationships Introduction to Relationships] - from the Getting Started Tutorial
* [[relationships.ini file]] reference
</content>
	<keywords>beforeAddRelatedRecord, Delegate class methods, relationship triggers</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=124">
	<page_name>beforeCopy</page_name>
	<page_id>124</page_id>
	<page_title>beforeCopy Delegate Class Method</page_title>
	<content>Return to [[Delegate class methods]]

[[toc]]

===Synopsis===

A delegate class method that will be executed before a record is copied using the copy set or copy selected function.  All xataface copies are shallow which means that related records are not copied by default.  If you want a more complex copy function for a table you can implement functionality in this hook.

Available since version 1.3

===Signature===
&lt;code&gt;
function beforeCopy( Dataface_Record $original, array $values);
&lt;/code&gt;

===Parameters===

* &apos;&apos;&apos;$original&apos;&apos;&apos; - The original record that is to be copied.
* &apos;&apos;&apos;$values&apos;&apos;&apos; - Associative array of values that are meant to be changed in the copy.  Keys correspond with column names.

===Returns===

* Either return nothing or you may return a PEAR_Error object to indicate that an error occurred with the copy.

==See Also==

* [[afterCopy]] - The afterCopy hook that can be implemented in the delegate class to run just after a record is copied.
</content>
	<keywords>beforeCopy, copy records</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=107">
	<page_name>beforeHandleRequest</page_name>
	<page_id>107</page_id>
	<page_title>beforeHandleRequest Application Delegate Class Method</page_title>
	<content>Return to [[Application Delegate Class]]

[[toc]]

===Synopsis===

The beforeHandleRequest method is a very useful hook that can be implemented in an [[Application Delegate Class]] to perform some processing before every request.  

This hook is called after user authentication is taken care of, but before control has been passed to the specific action.  This means that it is possible to do things such as change the current action or adjust query parameters depending on various factors.

===Example Uses===

* To require users to fill agree to license terms before they can visit particular parts of the application.
* To implement custom logging functionality to record user actions
* To change the default action for some or all tables.
* To automatically create user accounts in some cases.
* To change query parameters (e.g. default sorting etc...).

==Examples==

===Example 1: Changing the default action for a particular table===

&lt;code&gt;
class conf_ApplicationDelegate {
	
	function beforeHandleRequest(){
		$app = Dataface_Application::getInstance();
		$query =&amp; $app-&gt;getQuery();
			// Make sure you assign by reference (i.e. =&amp; )
			// for this if you want to make changes to the query
			
		if ( $query[&apos;-table&apos;] == &apos;dashboard&apos; and $app-&gt;_conf[&apos;using_default_action&apos;] ){
			$query[&apos;-action&apos;] = &apos;my_default_action&apos;;
		}
	}
}
&lt;/code&gt;

In the above example, we make use of the Application configuration variable [[using_default_action]] to find out if the request is using the default action.  This flag is set by Xataface if the user hasn&apos;t explicitly declared the action in the URL (i.e. -action has not explicitly been set).


==See Also==

* [[Application Delegate Class]]
* [http://dataface.weblite.ca/Dataface_Application Dataface_Application API Docs]
* [[Xataface URL Conventions]]
* &apos;&apos;&apos;[[Customizing Theme Based on IP Address]]&apos;&apos;&apos; - Article containing an example of using beforeHandleRequest hook.</content>
	<keywords>beforeHandleRequest, Application Delegate</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=13">
	<page_name>beforeRegister</page_name>
	<page_id>13</page_id>
	<page_title>beforeRegister</page_title>
	<content>==beforeRegister() Trigger==

A trigger that can be implemented in the [[Application Delegate Class]] or the [[Table Delegate Class]], to be executed before the registration form is saved.  This can be used to perform some custom actions like emailing the administrator.

===Signature===

function beforeRegister( Dataface_Record &amp;$record ) : mixed

====Parameters====

{| class=&quot;listing listing2&quot;
! Name
! Description
|-
| &amp;$record
| A Dataface_Record object encapsulating the record that is being inserted in the users table for this registration.
|-
| returns
| Mixed. If this method returns a PEAR_Error object, then registration will fail with an error.
|}

===Example===

&lt;code&gt;
&lt;?php
class conf_ApplicationDelegate {
    function beforeRegister(&amp;$record){
        // mail the admin to let him know that the registration is occurring.
        mail(&apos;admin@example.com&apos;, &apos;New registration&apos;, &apos;A new user &apos;.$record-&gt;val(&apos;username&apos;).&apos; has registered);
    }
}
&lt;/code&gt;

===See Also===

* [[afterRegister]]
* [[validateRegistrationForm]]
* [[sendRegistrationActivationEmail]]
* [[getRegistrationActivationEmailInfo]]
* [[getRegistrationActivationEmailSubject]]
* [[getRegistrationActivationEmailMessage]]
* [[getRegistrationActivationEmailParameters]]
* [[getRegistrationActivationEmailHeaders]]</content>
	<keywords></keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=109">
	<page_name>beforeSave</page_name>
	<page_id>109</page_id>
	<page_title>beforeSave Trigger</page_title>
	<content>Back to [[Delegate class methods]]

[[toc]]



===Synopsis===

The beforeSave trigger can be implemented in any table&apos;s [[delegate class|Delegate Class Methods]] to perform functionality that should be run *before* a record of that table is saved.  This is a useful place to insert additional field values depending on the input of the save record form.

This method is called both when records are inserted and when existing records are updated.  Some other triggers include [[beforeInsert]], [[beforeUpdate]], [[afterSave]], [[afterInsert]], and [[afterUpdate]], which do what you might expect.


===Method Signature===

&lt;code&gt;function beforeSave( Dataface_Record $record);&lt;/code&gt;

====Parameters====

# &apos;&apos;&apos;$record&apos;&apos;&apos; - The record that is about to be saved.  This is a [http://dataface.weblite.ca/Dataface_Record Dataface_Record] object.

====Returns====

# [http://dataface.weblite.ca/Dataface_Error Dataface_Error] on failure (if you want to cancel the save).


===Examples===

Given a table named &quot;people&quot;, suppose we wanted to automatically populate a field named &quot;full_name&quot;  with the concatenation of the &quot;first_name&quot; and &quot;last_name&quot; fields.  (Note you could also achieve a similar thing by making a calculated field for &quot;full_name&quot;, but for this example, we assume that we actually want to store this in the database.

We create a beforeSave() trigger that automatically updates the &quot;full_name&quot; field every time the record is saved.

In the &quot;people&quot; table delegate class (i.e. tables/people/people.php)
&lt;code&gt;
class tables_people {
    function beforeSave($record){
        $record-&gt;setValue(&apos;full_name&apos;, 
            $record-&gt;val(&apos;first_name&apos;).&apos; &apos;.$record-&gt;val(&apos;last_name&apos;)
        );
    }
}
&lt;/code&gt;

==See Also==

* [http://www.xataface.com/documentation/tutorial/getting_started/triggers Triggers section of the Xataface Getting Started Tutorial]
</content>
	<keywords>triggers, beforeSave,</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=102">
	<page_name>before_authenticate</page_name>
	<page_id>102</page_id>
	<page_title>before_authenticate hook</page_title>
	<content>Return to [[Application Delegate Class]]

The &apos;&apos;&apos;before_authenticate&apos;&apos;&apos; hook is a method that can be defined in the [[Application Delegate Class]] which is called before the authentication step occurs on &apos;&apos;&apos;every&apos;&apos;&apos; request (not just on login).  It is meant to be used to perform custom code that may affect the authentication settings.

===Since===

This hook has been available since Xataface Version 1.2.5.

===Example===

&lt;code&gt;
/**
 * Implemented trigger to be called before authentication to set the authentication
 * type to basic.
 */
function before_authenticate(){
    $auth = Dataface_AuthenticationTool::getInstance();
    if ( @$_SESSION[&apos;-login-type&apos;] == &apos;basic&apos; ) $auth-&gt;setAuthType(&apos;basic&apos;);
}
&lt;/code&gt;

In the above example we used a separate action to store the user&apos;s preferred login type in a session variable.  This preference is then applied in the before_authenticate method to override the authentication type.

===Chain Authentication Support===

The most common use of this hook is likely to implement some sort of chain authentication, where authentication methods are attempted until one succeeds. 

===See Also===

* [[Application Delegate Class]]
* [[authentication]] - Overview of Xataface authentication
* [[Writing Custom Authentication Plugins]]
* [[Authenticating Against the PHPBB Users Table]]
* [[LDAP or Active Directory]] - Using LDAP or Active Directory for authentication.
* [http://xataface.com/documentation/tutorial/getting_started/permissions Permissions Section of the Getting Started tutorial]
* [[_auth]] - Directives available in the [[_auth]] section of the [[conf.ini file]].</content>
	<keywords>authentication</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=55">
	<page_name>blob</page_name>
	<page_id>55</page_id>
	<page_title>blob</page_title>
	<content></content>
	<keywords></keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=11">
	<page_name>block__blockname</page_name>
	<page_id>11</page_id>
	<page_title>block__blockname</page_title>
	<content>===Available Blocks===

This is a grep to show the blocks that are defined in Xataface templates:

* Dataface_ActionsMenu.html:actions_menu_head
* Dataface_ActionsMenu.html:actions_menu_tail
* Dataface_Add_Existing_Related_Record.html:before_add_existing_related_record_form
* Dataface_Add_Existing_Related_Record.html:before_add_existing_related_`$ENV.relationship`_form
* Dataface_Add_Existing_Related_Record.html:after_add_existing_related_`$ENV.relationship`_form
* Dataface_Add_Existing_Related_Record.html:after_add_existing_related_record_form
* Dataface_Add_New_Related_Record.html:before_add_new_related_record_form
* Dataface_Add_New_Related_Record.html:before_add_new_related_`$ENV.relationship`_form
* Dataface_Add_New_Related_Record.html:after_add_new_related_`$ENV.relationship`_form
* Dataface_Add_New_Related_Record.html:after_add_new_related_record_form
* Dataface_AjaxEventDetails.html:before_event_details
* Dataface_AjaxEventDetails.html:after_event_details
* Dataface_Delete_Record.html:before_delete_record_form
* Dataface_Delete_Record.html:after_delete_record_form
* Dataface_Edit_Record.html:before_edit_record_form
* Dataface_Edit_Record.html:after_edit_record_form
* Dataface_FindForm.html:findform_before_`$element.field.name`_row
* Dataface_FindForm.html:findform_before_`$element.field.name`_widget
* Dataface_FindForm.html:findform_after_`$element.field.name`_widget
* Dataface_FindForm.html:findform_after_`$element.field.name`_row
* Dataface_FindForm.html:before_findform_table
* Dataface_FindForm.html:findform_before_`$element.field.name`_row
* Dataface_FindForm.html:findform_before_`$element.field.name`_widget
* Dataface_FindForm.html:findform_after_`$element.field.name`_widget
* Dataface_FindForm.html:findform_after_`$element.field.name`_row
* Dataface_FindForm.html:after_findform_table
* Dataface_Find_View.html:before_find_form
* Dataface_Find_View.html:after_find_form
* Dataface_Form_Section_Template.html:before_quickform_table
* Dataface_Import_RelatedRecords.html:before_import_related_records_form
* Dataface_Import_RelatedRecords.html:before_import_related_`$ENV.relationship`_form
* Dataface_Import_RelatedRecords.html:after_import_related_`$ENV.relationship`_form
* Dataface_Import_RelatedRecords.html:after_import_related_records_form
* Dataface_List_View.html:before_result_list
* Dataface_List_View.html:after_result_list
* Dataface_Login_Prompt.html:before_login_form
* Dataface_Login_Prompt.html:after_login_form
* Dataface_Main_Template.html:custom_stylesheets2
* Dataface_Main_Template.html:head
* Dataface_Main_Template.html:body_atts
* Dataface_Main_Template.html:before_body
* Dataface_Main_Template.html:before_header
* Dataface_Main_Template.html:after_header
* Dataface_Main_Template.html:before_search
* Dataface_Main_Template.html:after_search_form_submit
* Dataface_Main_Template.html:after_search
* Dataface_Main_Template.html:before_nav_menu
* Dataface_Main_Template.html:after_nav_menu
* Dataface_Main_Template.html:before_language_selector
* Dataface_Main_Template.html:after_language_selector
* Dataface_Main_Template.html:before_user_status_logged_in
* Dataface_Main_Template.html:after_user_status_logged_in
* Dataface_Main_Template.html:before_user_status_not_logged_in
* Dataface_Main_Template.html:after_user_status_not_logged_in
* Dataface_Main_Template.html:before_personal_tools
* Dataface_Main_Template.html:after_personal_tools
* Dataface_Main_Template.html:before_bread_crumbs
* Dataface_Main_Template.html:after_bread_crumbs
* Dataface_Main_Template.html:before_main_table
* Dataface_Main_Template.html:before_left_column
* Dataface_Main_Template.html:before_record_tree
* Dataface_Main_Template.html:after_record_tree
* Dataface_Main_Template.html:before_nav_menu
* Dataface_Main_Template.html:after_nav_menu
* Dataface_Main_Template.html:before_application_menu
* Dataface_Main_Template.html:after_application_menu
* Dataface_Main_Template.html:after_left_column
* Dataface_Main_Template.html:before_main_column
* Dataface_Main_Template.html:before_message
* Dataface_Main_Template.html:message
* Dataface_Main_Template.html:after_message
* Dataface_Main_Template.html:before_errors
* Dataface_Main_Template.html:error
* Dataface_Main_Template.html:after_errors
* Dataface_Main_Template.html:before_table_tabs
* Dataface_Main_Template.html:before_menus
* Dataface_Main_Template.html:after_menus
* Dataface_Main_Template.html:before_main_section
* Dataface_Main_Template.html:before_recently_viewed
* Dataface_Main_Template.html:after_recently_viewed
* Dataface_Main_Template.html:before_record_content
* Dataface_Main_Template.html:after_record_content
* Dataface_Main_Template.html:after_main_section
* Dataface_Main_Template.html:before_fineprint
* Dataface_Main_Template.html:after_fineprint
* Dataface_Main_Template.html:before_global_footer
* Dataface_Main_Template.html:after_global_footer
* Dataface_Main_Template.html:before_main_section
* Dataface_Main_Template.html:before_recently_viewed
* Dataface_Main_Template.html:after_recently_viewed
* Dataface_Main_Template.html:before_record_content
* Dataface_Main_Template.html:after_record_content
* Dataface_Main_Template.html:after_main_section
* Dataface_NavMenu.html:tables_menu_head
* Dataface_NavMenu.html:tables_menu_tail
* Dataface_NavMenu.html:tables_menu_head
* Dataface_NavMenu.html:tables_menu_tail
* Dataface_New_Record.html:before_new_record_form
* Dataface_New_Record.html:after_new_record_form
* Dataface_Record_Template.html:before_details_controller
* Dataface_Record_Template.html:after_details_controller
* Dataface_Record_Template.html:before_record_heading
* Dataface_Record_Template.html:after_record_heading
* Dataface_Record_Template.html:before_record_tabs
* Dataface_Record_Template.html:before_record_content
* Dataface_Record_Template.html:after_record_content
* Dataface_Record_Template.html:before_record_footer
* Dataface_Record_Template.html:after_record_footer
* Dataface_Registration.html:before_registration_form
* Dataface_Registration.html:after_registration_form
* Dataface_Related_Records_List.html:before_related_`$ENV.relationship`_records_list
* Dataface_Related_Records_List.html:after_related_`$ENV.relationship`_records_list
* Dataface_Remove_Related_Record.html:before_remove_related_record_form
* Dataface_Remove_Related_Record.html:before_remove_related_`$ENV.relationship`_record_form
* Dataface_Remove_Related_Record.html:after_remove_related_`$ENV.relationship`_record_form
* Dataface_Remove_Related_Record.html:after_remove_related_record_form
* Dataface_View_Record.html:before_view_tab_content
* Dataface_View_Record.html:before_record_actions
* Dataface_View_Record.html:after_record_actions
* Dataface_View_Record.html:after_view_tab_content
* Dataface_related_records_checkboxes.html:before_related_`$ENV.relationship`_records_checkboxes
* Dataface_related_records_checkboxes.html:before_related_records_checkboxes
* Dataface_related_records_checkboxes.html:after_related_records_checkboxes
* Dataface_related_records_checkboxes.html:after_related_`$ENV.relationship`_records_checkboxes
* Dataface_set_translation_status.html:before_details_controller
* Dataface_set_translation_status.html:after_details_controller

===Available Slots===

* Dataface_ActionsMenu.html:actions_menu
* Dataface_Add_Existing_Related_Record.html:add_existing_related_`$ENV.relationship`_form
* Dataface_Add_Existing_Related_Record.html:add_existing_related_record_form
* Dataface_Add_New_Related_Record.html:add_new_related_`$ENV.relationship`_form
* Dataface_Add_New_Related_Record.html:add_new_related_record_form
* Dataface_AjaxEventDetails.html:event_details
* Dataface_Delete_Record.html:delete_record_form
* Dataface_Edit_Record.html:edit_record_form
* Dataface_FindForm.html:findform_`$element.field.name`_row
* Dataface_FindForm.html:findform_`$element.field.name`_widget
* Dataface_FindForm.html:findform_`$element.field.name`_row
* Dataface_FindForm.html:findform_`$element.field.name`_widget
* Dataface_Find_View.html:find_form
* Dataface_Import_RelatedRecords.html:import_related_`$ENV.relationship`_form
* Dataface_Import_RelatedRecords.html:import_related_records_form
* Dataface_List_View.html:result_list
* Dataface_List_View_summary.html:result_list
* Dataface_Login_Prompt.html:login_form
* Dataface_Main_Template.html:doctype_tag
* Dataface_Main_Template.html:html_tag
* Dataface_Main_Template.html:html_head
* Dataface_Main_Template.html:html_title
* Dataface_Main_Template.html:dataface_stylesheets
* Dataface_Main_Template.html:custom_stylesheets
* Dataface_Main_Template.html:dataface_javascripts
* Dataface_Main_Template.html:custom_javascripts
* Dataface_Main_Template.html:head_slot
* Dataface_Main_Template.html:html_body
* Dataface_Main_Template.html:global_header
* Dataface_Main_Template.html:search_form
* Dataface_Main_Template.html:language_selector
* Dataface_Main_Template.html:user_status_logged_in
* Dataface_Main_Template.html:user_status_not_logged_in
* Dataface_Main_Template.html:personal_tools
* Dataface_Main_Template.html:bread_crumbs
* Dataface_Main_Template.html:main_table
* Dataface_Main_Template.html:left_column
* Dataface_Main_Template.html:application_menu
* Dataface_Main_Template.html:main_column
* Dataface_Main_Template.html:table_tabs
* Dataface_Main_Template.html:menus
* Dataface_Main_Template.html:main_section
* Dataface_Main_Template.html:record_content
* Dataface_Main_Template.html:fineprint
* Dataface_Main_Template.html:global_footer
* Dataface_Main_Template.html:main_section
* Dataface_Main_Template.html:record_content
* Dataface_Main_Templateold.html:doctype_tag
* Dataface_Main_Templateold.html:html_tag
* Dataface_Main_Templateold.html:html_head
* Dataface_Main_Templateold.html:html_title
* Dataface_Main_Templateold.html:dataface_stylesheets
* Dataface_Main_Templateold.html:custom_stylesheets
* Dataface_Main_Templateold.html:dataface_javascripts
* Dataface_Main_Templateold.html:custom_javascripts
* Dataface_Main_Templateold.html:head_slot
* Dataface_Main_Templateold.html:html_body
* Dataface_Main_Templateold.html:global_header
* Dataface_Main_Templateold.html:search_form
* Dataface_Main_Templateold.html:language_selector
* Dataface_Main_Templateold.html:user_status_logged_in
* Dataface_Main_Templateold.html:user_status_not_logged_in
* Dataface_Main_Templateold.html:personal_tools
* Dataface_Main_Templateold.html:bread_crumbs
* Dataface_Main_Templateold.html:main_table
* Dataface_Main_Templateold.html:left_column
* Dataface_Main_Templateold.html:application_menu
* Dataface_Main_Templateold.html:main_column
* Dataface_Main_Templateold.html:table_tabs
* Dataface_Main_Templateold.html:menus
* Dataface_Main_Templateold.html:main_section
* Dataface_Main_Templateold.html:record_content
* Dataface_Main_Templateold.html:fineprint
* Dataface_Main_Templateold.html:global_footer
* Dataface_Main_Templateold.html:main_section
* Dataface_Main_Templateold.html:record_content
* Dataface_NavMenu.html:tables_menu_options
* Dataface_NavMenu.html:tables_menu_options
* Dataface_New_Record.html:new_record_form
* Dataface_Record_Template.html:record_heading
* Dataface_Record_Template.html:record_content
* Dataface_Record_Template.html:record_footer
* Dataface_Registration.html:registration_form
* Dataface_Related_Records_List.html:before_related_list
* Dataface_Related_Records_List.html:related_`$ENV.relationship`_records_list
* Dataface_Related_Records_List.html:related_records_list
* Dataface_Related_Records_List.html:after_related_list
* Dataface_Remove_Related_Record.html:remove_related_`$ENV.relationship`_record_form
* Dataface_Remove_Related_Record.html:remove_related_record_form
* Dataface_View_Record.html:view_tab_content
* Dataface_View_Record.html:record_actions
* Dataface_View_Record.html:record_search
* Dataface_View_Record.html:`$section.name`_section_content
* Dataface_View_Record.html:record_view_main_section
* Dataface_View_Record.html:`$section.name`_section_content
* Dataface_related_records_checkboxes.html:related_`$ENV.relationship`_records_checkbox_form
* Dataface_related_records_checkboxes.html:related_records_checkbox_form
* global_header.html:site_logo

</content>
	<keywords></keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=179">
	<page_name>Cached_permissions</page_name>
	<page_id>179</page_id>
	<page_title>Cached Permissions</page_title>
	<content>==Cached Permissions==

===Introduction===
When you insert a SQL query in your getPermissions function, this will slow down the app dramatically because this function is called by each query. To resolve this problem, it is better to use cached permissions in your /conf/ApplicationDelegate.php or table/table.php.

===Procedure===
Here is an example :
&lt;code&gt;
class tables_mytable {

    private $cachedPerms = null;
    private function _getCachedPerms($param1, $param2, ..., $paramN){
        if ( !isset($this-&gt;cachedPerms) ) {
            $this-&gt;cachedPerms = array();
            // do some stuff
            $res = mysql_query(&quot;select * from foo where bar=1 and param2=&apos;&quot;.addslashes($param2).&quot;&apos;&quot;);
            while ( $row = mysql_fetch_assoc($res) )  $this-&gt;cachedPerms[$row[&apos;fooid&apos;]] = $row;
        }
        return $this-&gt;cachedPerms;
    }

    function getPermissions($record){
        // do some stuff
        $perms = $this-&gt;getCachedPerms($param1, $param2, ..., $paramN);
        return $perms;
    }
}&lt;/code&gt;
Here, getPermissions() will run a db query on its first request, but subsequent requests will just load the cached value.</content>
	<keywords>permissions, cache, quick, query</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=100">
	<page_name>calendar</page_name>
	<page_id>100</page_id>
	<page_title>Calendar Widget</page_title>
	<content>Back to [[widget:type]]

[[toc]]

===Synopsis===

The calendar widget is the default widget for editing date and datetime fields.  It is javascript pop-up calendar that allows users to select date and time visually.  It can be configured to allow different date and time formats, themes, starting days of the week, and more.

[[image:http://media.weblite.ca/files/photos/calendar_widget.png?max_width=400]]

===Usage===

For DATE and DATETIME fields, the calendar widget is the default widget used, so you need not specify it explicitly in the fields.ini file.  For other types of fields you may designate them to use the calendar widget in the [[fields.ini file]] as follows:

&lt;code&gt;
[my_field]
    widget:type=calendar
&lt;/code&gt;

===Configuration Options===

The calendar widget supports some configuration options that can be set in the [[fields.ini file]].  These options are as follows:

{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Default
! Version
|-
| [[widget:lang]]
| The language to use for the calendar.  This is a 2-digit ISO language code.
| en
| 0.5.3
|-
| [[widget:theme]]
| The theme to use for the calendar.  It only ships with one theme at present.
| calendar-win2k-2
| 0.5.3
|-
| [[widget:firstDay]]
| The first day of the week  (e.g. Monday=1)
| 1
| 0.5.3
|-
| [[widget:showsTime]]
| Boolean value indicating whether the calendar should show the time as well.
| 0 for DATE fields, 1 for DATETIME fields.
| 0.5.3
|-
| [[widget:ifFormat]]
| The input format of the date.  This takes a formatting string as supported by [http://ca2.php.net/strftime the strftime function].
| %Y-%m-%d %I:%M %P
| 0.5.3
|-
| [[widget:timeFormat]]
| Whether to use 12 hour or 24 hour time format.
| 12
| 0.5.3
|}

===Examples===

====Setting the time to use 24 hour format====

In your [[fields.ini file]]:
&lt;code&gt;
[my_field]
    wiget:type=calendar
    widget:timeFormat = 24
&lt;/code&gt;


===See Also===

* [[date]] Widget - A widget for editing date and time using select drop-down lists.
* [[time]] Widget - A widget for selecting time from a set of possibilities in a single select list.</content>
	<keywords>calendar widget, fields.ini file, widget:type</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=43">
	<page_name>Calendar_Action</page_name>
	<page_id>43</page_id>
	<page_title>Calendar_Action</page_title>
	<content>==Calendar Action==

[[toc]]

Xataface 1.0 includes a built-in calendar action that is disabled by default.  If enabled, it allows you to view the records in any found set as a calendar of events, as follows:

&lt;nowiki&gt;
&lt;div style=&quot;text-align:center;border: 1px solid #ccc; padding: 10px&quot;&gt;
&lt;img src=&quot;http://media.weblite.ca/files/photos/Picture -4.png?max_width=500&quot;
onmouseover=&quot;this.src=&apos;http://media.weblite.ca/files/photos/Picture -4.png&apos;;&quot;
onmouseout=&quot;this.src=&apos;http://media.weblite.ca/files/photos/Picture -4.png?max_width=500&apos;;&quot;/&gt;
&lt;/div&gt;
&lt;/nowiki&gt;

===Features===

* Monthly display
* Hourly schedule for any day by clicking on it.
* Show record details instantly by clicking on it in the calendar.
* Recognizes dates, start and end times for records when interpreted as calendar events.
* Respects searches (i.e. you can filter the records and the calendar will only show those records in the found set).

===Requirements===

Your table records should contain at least dates in order for them to be interpreted as events that can be placed in a calendar.

===Setting up the Calendar===

Suppose I have a table called &apos;&apos;Lessons&apos;&apos; that stores information about scheduled music lessons.  If I want to add the calendar to this table, then I would add an &apos;&apos;[[actions.ini file]]&apos;&apos; to the &apos;&apos;tables/Lessons&apos;&apos; directory with the following contents:&lt;code&gt;
[calendar &gt; calendar]
    condition=&quot;true&quot;
&lt;/code&gt;
This overrides the calendar action which is disabled by default, and enables it for the &apos;&apos;Lessons&apos;&apos; table.

Next I need to inform Xataface which fields store the event dates and times so that the records can be laid out in the calendar appropriately.  (Note that if you skip this step, Xataface will make a best guess based on column types and names - but it is better to specify these explicitly).

In the &apos;&apos;Lessons&apos;&apos; table I have the following fields that are relevant here:

* &apos;&apos;lesson_date&apos;&apos; - A date field containing the date and start time of the event.
* &apos;&apos;start_time&apos;&apos; - A time field with the start time of the lesson.

We can tell Xataface to treat these fields accordingly by adding the following directives to the appropriate field sections of the [[fields.ini file]] for the &apos;&apos;Lessons&apos;&apos; table:

* &apos;&apos;event.date=1&apos;&apos; - Specifies that the field stores the date of the event.
* &apos;&apos;event.start=1&apos;&apos; - Specifies that the field stores the start time of the event.

So in our case we&apos;ll modify the [[fields.ini file]] as follows:

&lt;code&gt;
[lesson_date]
    event.date=1

[start_time]
    event.start=1
&lt;/code&gt;

Now if we load up our application, we should now see a &apos;&apos;calendar&apos;&apos; tab along side &apos;&apos;list&apos;&apos;, &apos;&apos;details&apos;&apos;, and &apos;&apos;find&apos;&apos; for the &apos;&apos;Lessons&apos;&apos; table.  Click on this tab to see your records displayed in a calendar.

===Using a datetime field to store both date and start time===

You can also use a single field to store both the date and start time for an event.  In this case you just provide the &apos;&apos;event.date&apos;&apos; and &apos;&apos;event.start&apos;&apos; directives for the same field.  For example if the &apos;&apos;lesson_date&apos;&apos; was a datetime field that marked the date and time of the lesson, we would modify our [[fields.ini]] file as follows:

&lt;code&gt;
[lesson_date]
    event.date=1
    event.start=1
&lt;/code&gt;

===Available Fields===

The Calendar action will look for the following pieces of information in your records:

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| event.date
| Indicates that the field contains the date of the event.
| 1.0
|-
| event.start
| Indicates that the field contains the start time of the event.
| 1.0
|-
| event.end
| Indicates that the field contains the end time of the event.
| 1.0
|-
| event.location
| Indicates that the field contains the location of the event.
| 1.0
|-
| event.category
| Indicates that the field contains the category of the event.
| 1.0
|}</content>
	<keywords></keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=69">
	<page_name>checkbox</page_name>
	<page_id>69</page_id>
	<page_title>checkbox</page_title>
	<content>==The checkbox widget==

In the [[fields.ini file]] you can specify a field to be edited using a checkbox widget by setting [[widget:type]] to [[checkbox]].  A checkbox widget can function in 2 different ways depending on the parameters that you assign to the field.

[[toc]]

===Example 1: A TinyInt (boolean) field===

Suppose our table has a tinyint field named &quot;Active&quot; which specifies whether the record is currently in use.  This field will store a value of either 0 or 1.  So we configure this field in our [[fields.ini]] file to use a checkbox widget as follows:

&lt;code&gt;
[Active]
  widget:type=checkbox
&lt;/code&gt;

Results:

[[Image:http://media.weblite.ca/files/photos/Picture%2024.png?max_width=640]]

===Example 2: A repeating field (multiple checkboxes for one field===

Checkboxes can store multiple values in a single field by setting the [[vocabulary]] directive and applying it to a varchar or text field.  In this case there will be one value saved per line.  

In this example, suppose we have a varchar field named &apos;&apos;&apos;categories&apos;&apos;&apos; which uses the &apos;&apos;&apos;categories&apos;&apos;&apos; [[valuelist]] to specify the different categories that can be checked at any given time.  Our [[valuelists.ini file]] might look like:
&lt;code&gt;
[categories]
    __sql__ = &quot;select id,name from categories&quot;
&lt;/code&gt;

And our [[fields.ini file]] looks like:
&lt;code&gt;
[categories]
    widget:type=checkbox
    vocabulary=categories
&lt;/code&gt;
* Note that you don&apos;t need to name the field the same as the valuelist.  It just worked out this way.

Now if we save a record with categories 1, 3, and 5 checked, then the categories column of our row in the database will store something like:
&lt;code&gt;
1
3
5
&lt;/code&gt;
i.e. one category id per line.  Note that using this method, your database will not be normalized because you are storing multiple values in a single field.  However in many applications this is sufficient.

Results:

[[Image:http://media.weblite.ca/files/photos/Picture%2025.png?max_width=640]]

===Example 3: Using a &quot;Categories&quot; relationship===

&quot;&quot;&quot;(Note: This example requires Xataface version 1.2 or higher)&quot;&quot;&quot;

Example 2 above shows how we can easily add and remove a record from multiple categories using checkboxes.  However it required multiple pieces of information to be stored in a single database field which may or may not be advantageous for your database design.  If you&apos;re looking for a more normalized database schema you would probably design your database as follows for this case:

# Books table - Stores all of the books.
# Categories table - Stores all of the categories
# Book_Categories table - Stores mapping of books to categories.

With out table structure we will first want to define a relationship from Books to Categories to reflect the connection between books and categories.  The [[relationships.ini file]] for this might look like:

&lt;code&gt;
[categories]
    Books.Book_ID=&quot;$Book_ID&quot;
    Book_Categories.Category_ID=Categories.Category_ID
&lt;/code&gt;

And our [[fields.ini file]] for the Books table might look like:
&lt;code&gt;
[categories]
    widget:type=checkbox
    transient=1
    relationship=categories
&lt;/code&gt;
* Note that there is no need for our field to be named the same as our relationship.  It just turned out this way.  Also note that we used the transient=1 flag here because the Books table no longer has a categories field in the database.  This field is defined purely for the benefit of the edit form so that we will get a checkbox group to select the book&apos;s categories.

Results:
[[Image:http://media.weblite.ca/files/photos/Picture%2025.png?max_width=640]]

==Related Parameters==

# [[vocabulary]] - Assigns a valuelist to be used as the options for this checkbox group.
# [[repeat]] - A boolean value indicating whether this field should be treated as a &apos;repeating field&apos;.  A repeating field is one with multiple checkboxes.  By default the checkbox widget operates as a single checkbox that controls a boolean value.
# [[relationship]] - (Only applicable to [[transient]] fields).  If the [[relationship]] directive is set then this field can be used to add/remove records from a relationship.</content>
	<keywords></keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=178">
	<page_name>Clean_the_html_for_the_export</page_name>
	<page_id>178</page_id>
	<page_title>Clean the HTML to export data</page_title>
	<content>==Clean HTML tags and entities to export your data==
#Override the display() of the field to strip the tags... but this would affect all parts of the application where the HTML fields are displayed.
#Create a grafted field, then override its display to show the stripped contents of the HTML area field.

e.g. in the fields.ini:

&lt;code&gt; 
    __sql__ = &quot;select t.*, null as stripped_field from mytable t&quot;
    [original_field]
       widget:type=htmlarea
       visibility:csv=hidden

    [stripped_field]
        visibility:csv = visible
        visibility:list=hidden
        visibility:browse=hidden
        visibility:find=hidden

&lt;/code&gt; 


Then in the delegate class:


&lt;code&gt; 
    function stripped_field__display($record){
        return html_entity_decode(strip_tags($record-&gt;val(&apos;original_field&apos;)), ENT_QUOTES, &apos;UTF-8&apos;);
    }
&lt;/code&gt; </content>
	<keywords></keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=182">
	<page_name>column:legend</page_name>
	<page_id>182</page_id>
	<page_title></page_title>
	<content></content>
	<keywords></keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=25">
	<page_name>conf.ini_file</page_name>
	<page_id>25</page_id>
	<page_title>conf.ini_file</page_title>
	<content>==conf.ini File==

[[toc]]

The conf.ini file is where most of the application-level configuration information is stored for a Xataface application.  It contains information such as:

* database connection information
* which tables should appear in the tables menu.
* [[preferences|preference settings]]
* [[authentication]] settings
* which add-on [[modules]] are to be used
* output caching settings
* history/undo settings
* other misc settings.

Every conf.ini file must contain at least the following sections:


{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Version
|-
| _database
| Contains database connection info.
| all
|-
| _tables
| Contains a list of tables that are to be included in the navigation menu of the application.
| all
|}


The following optional sections may also be included:

{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Version
|-
| [http://xataface.com/documentation/how-to/disallow_tables _allowed_tables]
| Specifies tables that should be explicitly allowed to override disallowed tables listed or matched in the [http://xataface.com/documentation/how-to/disallow_tables _disallowed_tables] section.
| 0.7
|-
| [[_auth]]
| Contains information about [[authentication]].
| 0.6
|-
| [http://xataface.com/documentation/how-to/disallow_tables _disallowed_tables]
| A list of tables or patterns that match tables that should be blocked from being accessed directly through the application.  By default any table beginning with an underscore, &apos;dataface_&apos;, or ending in &apos;__history&apos; are blocked.  This prevents unintended access to some of the automatically created tables in Xataface.
| 0.7
|-
| _feed
| Configuration options for [[Introduction_to_RSS_Feeds_in_Xataface|RSS feeds]] that are generated by the application.
| 1.0
|-
| _history
| Settings pertaining to the [http://xataface.com/documentation/how-to/history-howto history feature] (e.g. whether it has been enabled).
| 0.7
|-
| _index
| Settings for the full site search indexing.
| 1.0
|-
| _modules
| A list of [[modules]] that are enabled for this application.
| 1.0
|-
| [[_output_cache]]
| Output cache settings.  Using output caching can dramatically improve performance for busier sites.
| 0.8
|-
| _themes
| A list of the themes that are to be applied to the application.
| 0.8
|}

===Stand-alone Attributes===

Stand-alone attributes for an INI file must appear at the beginning of the INI file (before any of the sections).  The conf.ini may contain the following stand-alone attributes.

{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Values
! Version
|-
| cache_queries
| Enables query caching.  Enabling this feature can yield drastic performance improvements especially on busy sites with large databases.
| boolean (0 or 1)
| 1.2

|-
| cache_queries_log
| Enables logging of query caching to the file /tmp/querylog.log so that you can tell whether your queries are being cached, and which ones are being cached.
| boolean (0 or 1)
| 1.2

|-
| default_action
| The default action to be performed if it is not explicitly specified in the query (e.g. &apos;list&apos;, &apos;find&apos;, &apos;edit&apos;).  Default is &apos;list&apos;.
| string
| 0.6
|-
| debug
| If this is set to 1, then the application will run in debug mode which displays the available slots and blocks on the screen, along with some other debug information.
| 0 or 1 (default is 0)
| 0.6

|-
| default_browse_action
| The default action to perform in the details tab.  E.g. When you click on the &quot;details&quot; tab there are a number of sub-tabs including &apos;view&apos;, &apos;edit&apos;, etc... .   The default value for this directive is &apos;view&apos;.  If you want to go directly to the edit form when clicking on a record in list view, you would set &apos;&apos;default_browse_action&apos;&apos; to &apos;edit&apos;.
| string
| 0.6
|-
| default_language
| The default language to use.  This is the 2-digit ISO language code.  If this value is not specified it defaults to the first language listed in the &apos;&apos;[languages]&apos;&apos; section.
| string (2-digit ISO language code)
| 0.6
|-
| default_limit
| The default limit (i.e. the number of records to show per page) if none is explicitly specified in the query.  Default is 30.
| int
| 0.6
|-
| default_table
| The default table to show if none is specified by the query.  If you do not define this value, then the first table in the &apos;&apos;[_tables]&apos;&apos; section is used.
| string
|0.6
|-
| disable_session_ip_check
| Default behaviour automatically tracks the IP address of the user when they log in.  If a request is made for a session from a different IP then the session is automatically destroyed and the user is logged out.
| boolean
| 1.3rc4

|-
| title
| A title for the application (appears in the browser title bar).
| string
| 0.6
|-
| usage_mode
| The usage mode of the application.  If this value is set to &apos;&apos;edit&apos;&apos;, then ajax inline editing is enabled (i.e. you can click on any value in the application to edit it inline.
| &apos;view&apos; or &apos;edit&apos;
| 0.6
|}

===Example 1: A simple conf.ini file===

&lt;code&gt;
[_database]
	host=&quot;localhost&quot;
	name=&quot;mydb&quot;
	user=&quot;mydbuser&quot;
	password=&quot;foo&quot;
	
[_tables]
webpage_sites=&quot;Websites&quot;
translations = &quot;Translations&quot;
packages=&quot;Packages&quot;
users=Users
proof_jobs=&quot;Jobs&quot;
webpage_status=&quot;Webpages Status&quot;

&lt;/code&gt;

===Example 2: A more complex conf.ini file===

&lt;code&gt;
;debug=1
;default_action=home
;google_translate_url=&quot;http://weblite-dns2.com/proxy.php&quot;
google_translate_url=&quot;http://ec2-75-101-244-123.compute-1.amazonaws.com/proxy.php&quot;
title=&quot;Web Lite Translate&quot;
default_price_per_word=0.15

;;Configuration settings for application
title=&quot;translation_weblite_ca&quot;
scriptUrl=&quot;http://translation.weblite.ca/index.php&quot;
multilingual_content=1


[_database]
	host=&quot;localhost&quot;
	name=&quot;mydb&quot;
	user=&quot;mydbuser&quot;
	password=&quot;foo&quot;
	
[_tables]
    webpage_sites=&quot;Websites&quot;
    translations = &quot;Translations&quot;
    packages=&quot;Packages&quot;
    users=Users
    proof_jobs=&quot;Jobs&quot;
    webpage_status=&quot;Webpages Status&quot;


[_auth]
	users_table=users
	username_column=username
	password_column=password
	secret_code=&quot;ljkasdfjkldsafliasdoiudsfoi&quot;
	allow_register=1
	session_timeout=999999999
	
[_modules]
	modules_ShoppingCart=&quot;modules/ShoppingCart/ShoppingCart.php&quot;

[ShoppingCart_taxes]
	;; This section is necessary to declare that we have NO taxes.
	
[metatags]
	keywords = &quot;translation, translate&quot;
	description = &quot;Good translation service&quot;
	
;[_output_cache]
;	enabled=1

[_mail]
	func=mail2
	
&lt;/code&gt;

</content>
	<keywords></keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=110">
	<page_name>Contribute_to_Xataface_Translation_Project</page_name>
	<page_id>110</page_id>
	<page_title>How to Contribute Translations</page_title>
	<content>[[toc]]

==Synopsis==

Xataface stores its translations in INI files in its lang directory, one for each language.  You can develop your own translation by first copying the en.ini file to xx.ini (where xx is the ISO language code for the language you are translating for), then modifying the translations into your target language. &apos;&apos;&apos;NOTE: THIS IS NOT THE PREFERRED WAY TO CONTRIBUTE TRANSLATIONS.  PLEASE SEE &quot;Adding Translations Using Google Spreadsheets&quot; BELOW&apos;&apos;&apos;.

==Anatomy of a Language .INI file==

The language .INI files (e.g. en.ini, es.ini, etc...) consist of key-value pairs, where the key is a unique identifier for a string in Xataface, and the value is the translation.  All language files should contain the same keys, however if you omit a key from your translation, Xataface will just fall back to the default value that is defined in the PHP source code.

===Example Snippet from en.ini file===

&lt;code&gt;
scripts.GLOBAL.FORMS.OPTION_PLEASE_SELECT = &quot;Please Select ...&quot;
save_button_label = &quot;Save&quot;
scripts.GLOBAL.MESSAGE.PERMISSION_DENIED = &quot;Permission Denied&quot;
scripts.GLOBAL.NO_RECORDS_MATCHED_REQUEST = &quot;No records matched your request.&quot;
&lt;/code&gt;

In this small segment you can see 4 strings that are translated.  The values on the left of the equals sign are the keys.  Their corresponding values are on the right of the equals signs.  A corresponding segment of the fr.ini (French) language file looks like:

&lt;code&gt;
scripts.GLOBAL.FORMS.OPTION_PLEASE_SELECT = &quot;SVP sélectionnez ...&quot;
save_button_label = &quot;Enregistrer&quot;
scripts.GLOBAL.MESSAGE.PERMISSION_DENIED = &quot;Permission Refusée&quot;
scripts.GLOBAL.NO_RECORDS_MATCHED_REQUEST = &quot;Aucun résultat ne correspond à votre requête.&quot;
&lt;/code&gt;

You can see that the keys (the values on the left) are identical to those in the en.ini snippet.  Only the values are changed (translated) into French.

&apos;&apos;&apos;NOTE: IT IS BETTER TO USE GOOGLE SPREADSHEETS TO EDIT TRANSLATIONS, THAN TO WORK WITH INI FILES DIRECTLY. PLEASE SEE &quot;Adding Translations Using Google Spreadsheets&quot; BELOW&apos;&apos;&apos;


==Gotchas: Things to watch out for==

When editing or adding translations in INI files, you need to be aware of a few gotchas related to how INI files work.  If you mess up a line by forgetting to add a quote, you could cause a parse error which would cause Xataface to ignore the language file altogether.  The following are a few common pitfalls:

===Use UTF-8 Encoding===

All ini files should use UTF-8 encoding, so make sure you are using a text editor that supports UTF-8 if you want to edit INI files.  (But it is better to just use Google Spreadsheets for the editing if possible, in which case you don&apos;t have to worry about this).

===Wrap Translations in Double Quotes===

All translations should be wrapped in double quotes.  E.g.
&lt;code&gt;
mykey=&quot;My Value&quot;
&lt;/code&gt;

If you forget to close a quote, it will likely cause a parse error and Xataface will fail to load the file.  E.g.
&lt;code&gt;
mykey=&quot;My Value
&lt;/code&gt;
would be a problem.


===Can&apos;t Use Double Quotes as Part of the Translation===

Since INI files use double quotes to wrap strings, you can&apos;t use a double quote inside your translation.  E.g. you can&apos;t do this:
&lt;code&gt;
mylink=&quot;&lt;a href=&quot;http://google.com&quot;&gt;Google&lt;/a&gt;&quot;
&lt;/code&gt;
because of the inline double quotes.

One way around this is to try to use single quotes where possible.  E.g.
&lt;code&gt;
mylink=&quot;&lt;a href=&apos;http://google.com&apos;&gt;Google&lt;/a&gt;&quot;
&lt;/code&gt;

Another way around this is to the &apos;&apos;&quot;_Q&quot;&apos;&apos; key sequence, which Xataface will
automatically convert to a double quote for you at runtime.  E.g. You could do:
&lt;code&gt;
mylink=&quot;&lt;a href=&quot;_Q&quot;http://google.com&quot;_Q&quot;&gt;Google&lt;/a&gt;&quot;
&lt;/code&gt;

&apos;&apos;&apos;NOTE: If you use Google Spreadsheets to edit your translations, you won&apos;t have this problem.  You can use double quotes inside your translations.  The [[csv2ini]] tool will automatically convert these to an appropriate form when the spreadsheet is converted to the INI files.&apos;&apos;&apos;


===Leave Variables Alone===

Some translated strings include variables that are meant to be replaced by Xataface at runtime.  These should be left intact across translations.  You can identify a variable by their resemblance to PHP variables (prefixed with a $).

E.g. In the en.ini file, the translation:
&lt;code&gt;
No action found = &quot;No action found named &apos;$name&apos;&quot;
&lt;/code&gt;
has the variable &apos;&apos;$name&apos;&apos;.

So the French translation should maintain this variable.  E.g. in the fr.ini file:
&lt;code&gt;
No action found = &quot;Aucune action nommée &apos;$name&apos;&quot;
&lt;/code&gt;


==Adding Translations Using Google Spreadsheets==

In order to help keep translations more up to date, we have developed a set of tools to enable us to use Google Spreadsheets to edit and add translations, and convert these spreadsheets on demand into an appropriate set of language INI files.

The spreadsheet containing the Xataface translations is public to view and is located  [https://spreadsheets.google.com/ccc?key=0AqJNZUI7flxSdFVLWDlnVVpQZ3dMaGZhVjVHN2c3bEE&amp;hl=en here].  If you would like to add your own translations or modify existing translations, please contact [mailto:steve@weblite.ca Steve Hannah] so that you can be given editor permission.  You will first need a google docs account, then we can give you permission to edit the spreadsheet.

This centralized spreadsheet is converted to INI files and merged into SVN before every release.  You can also export this spreadsheet as a CSV and convert it to Xataface&apos;s language INI files yourself using the [[csv2ini]] tool that is located in the tools directory of the Xataface distribution.


===Gotchas with Google Spreadsheets===

Editing translations with Google Spreadsheets is much safer than editing the INI files directly.  You don&apos;t have to worry about encoding issues, and you don&apos;t have to dance around double quotes like you do with INI files.  There is only one known thing to watch out for:

====Starting a translation with a Single Quote====

If you start a translation with a single quote, Google Spreadsheets will interpret this as a directive to indicate that the contents of that cell should be considered a string (and not a number for example).  E.g. If you enter the following into a Google Spreadsheets cell:
&lt;code&gt;
&apos;Help!&apos;, I exclaimed
&lt;/code&gt;
If you unfocus from that cell it will only say:
&lt;code&gt;
Help!&apos;, I exclaimed
&lt;/code&gt;
If you go back into edit mode of the cell again, you&apos;ll see your opening single quote again... and when you tab out, it will disappear again.  

You can work around this issue by just using two single-quotes for the first quote.  E.g.:
&lt;code&gt;
&apos;&apos;Help!&apos;, I exclaimed
&lt;/code&gt;

This way Google will interpret the first quote as a directive, and it will use the second one as an actual single quote.


====Converting the Google Translation Spreadsheet into INI Files====

So you&apos;ve contributed a number of translations to the [https://spreadsheets.google.com/ccc?key=0AqJNZUI7flxSdFVLWDlnVVpQZ3dMaGZhVjVHN2c3bEE&amp;hl=en Xataface Translations Google Spreadsheet], and you want to be able to use them in your installation of Xataface before the next release.  Just follow the steps below:

# Download the spreadsheet as a CSV file, using the &apos;&apos;File&apos;&apos; &gt; &apos;&apos;Download as&apos;&apos; &gt; &apos;&apos;CSV (Current Sheet)&apos;&apos; menu item in Google Spreadsheets.
# Run the [[csv2ini]] PHP script located in the xataface/tools directory to convert the xataface-translations.csv file that you downloaded from Google Spreadsheets in the previous step into INI files.  The conversion command looks like:
&lt;code&gt;
$ php /path/to/xataface/tools/csv2ini.php /path/to/xataface-translations.csv /path/to/destination/dir/
&lt;/code&gt;

This will convert the xataface-translations.csv file into a set of language INI files and place them the specified destination directory  (don&apos;t forget the trailing slash) on /destination/dir so that the script knows its a directory.  You can then copy these INI files into your xataface/lang directory to make them live.

&apos;&apos;&apos;Note: the [[csv2ini]] script has only been used in a unix/os x type environment.  Some small modifications would probably be necessary to make them work on Windows.&apos;&apos;&apos;




</content>
	<keywords>Translations, Google Spreadsheets, en.ini, fr.ini</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=57">
	<page_name>Creating_a_Dashboard</page_name>
	<page_id>57</page_id>
	<page_title>Creating_a_Dashboard</page_title>
	<content>==Creating a Dashboard for your Users==

[[toc]]

Xataface allows you to build powerful data-driven applications quickly, but these applications may be daunting to your users if they don&apos;t know what they can do with the application.  Most applications provide some sort of dashboard or control panel with some introductory instructions and links to commonly used actions in the application.  This makes the application more intuitive for users so that they can start using it right away, even without instruction from the developer.

===Characteristics of a Dashboard===

# Should be the default page when someone visits the application.
# Should be customized to show menus and content that are relevant to the current user.  (i.e. different users may see different links and content on their dashboard).
# Should contain at least some basic instructions so that the user understands what the application does when he visits the dashboard for the first time.
# Should contain links to frequently used actions.

===Strategies: 8 ways to skin the cat===

There are many viable strategies for adding a dashboard to your Xataface application.  This article presents only one.  It has been chosen because it satisfies all of the desired characteristics of a dashboard listed above, and it is easy to implement.

This strategy involves the following components:

# Create a dummy &apos;&apos;dashboard&apos;&apos; table.
# Create a dashboard action and associated template.
# Make sure our dashboard action is the default action for our application (more complex than just using the [[default_action]] directive in the [[conf.ini file]].

==Our Sample Application==

Consider our sample application, a publications management system for professors and research groups at a university.  It allows users to manage their publications using either BibTex format or a web-based form, and embed those publications into their webpage in a slick sortable format.  Currently, when the user accesses the application for the first time, they are shown the &apos;&apos;list&apos;&apos; tab of the &apos;&apos;bibliographies&apos;&apos; table.  This isn&apos;t all that informative and it may not be obvious to the user that their first step should be to create a new bibliography via the &apos;&apos;new record&apos;&apos; button.  Ideally we would like the user to go directly to a dashboard page with options to:

# Add New Bibliography
# Edit an Existing Bibliography
# Embed a Bibliography into their Webpage

And we want some basic instructions so that the user knows what to do when they first access the page.

==The Steps==

To create this dashboard we will follow the steps listed below (and mentioned above in the &apos;&apos;strategies&apos;&apos; section.

===Step 1: Create a dummy &apos;&apos;dashboard&apos;&apos; table===

This may seem unorthodox but it just happens to make our lives easier in the long run.  By creating a dummy table we are able to cause that table to be listed first in the &apos;&apos;_tables&apos;&apos; section of the [[conf.ini file]] and thus be the default table when users visit our application.

&lt;code&gt;
CREATE TABLE dashboard (
    dashboard_id int(11) not null auto_increment primary key
);
INSERT INTO dashboard values (1);
&lt;/code&gt;

===Step 2: Make &apos;&apos;dashboard&apos;&apos; table default===

We now modify the conf.ini file to list the &apos;&apos;dashboard&apos;&apos; table first:
&lt;code&gt;
[_tables]
    dashboard=Dashboard
    bibliographies=Bibliographies
&lt;/code&gt;

===Step 3: Create a Dashboard action and associated template===

This is the step where we actually create our dashboard action.  There are three parts to this story:

====Creating Action PHP Class====

The actual action will be located in the &apos;&apos;actions/dashboard.php&apos;&apos; file of our application, and looks like:

&lt;code&gt;
&lt;?php
class actions_dashboard {
    function handle(&amp;$params){
        $bibs = df_get_records_array(&apos;bibliographies&apos;, array());
        df_display(array(&apos;bibliographies&apos;=&gt;$bibs), &apos;dashboard.html&apos;);
    }
}
&lt;/code&gt;

All this does is loads the &apos;&apos;bibliographies&apos;&apos; records owned by the current user. Elsewhere we are using security filters so that the user can only see &apos;&apos;his&apos;&apos; bibliographies, which is why we don&apos;t need to specify any query here in the &apos;&apos;df_get_records_array&apos;&apos; function.

It then passes those bibliographies to the &apos;&apos;dashboard.html&apos;&apos; template that we create next.

====Creating the Action&apos;s Template====

The template for our action is located in the &apos;&apos;templates/dashboard.html&apos;&apos; file:
&lt;code&gt;
{use_macro file=&quot;Dataface_Main_Template.html&quot;}
    {fill_slot name=&quot;main_column&quot;}
        &lt;h1&gt;Welcome to the BibTeX Publication Management System (BPMS)&lt;/h1&gt;
        
        &lt;p&gt;This system allows you to manage your publications and publish
        them on the web.  Some common actions you may perform with this system
        include:
            &lt;ul&gt;
                &lt;li&gt;&lt;img src=&quot;{$ENV.DATAFACE_URL}/images/add_icon.gif&quot;/&gt;
                    &lt;a href=&quot;{$ENV.DATAFACE_SITE_HREF}?-table=bibliographies&amp;-action=new&quot;&gt;
                        Create New Bibliography&lt;/a&gt;
                &lt;/li&gt;
                &lt;li&gt;&lt;img src=&quot;{$ENV.DATAFACE_URL}/images/edit.gif&quot;/&gt; 
                   Edit existing bibliography: 
                   &lt;select onchange=&quot;window.location.href=this.options[this.selectedIndex].value&quot;&gt;
                    &lt;option value=&quot;&quot;&gt;Select ...&lt;/option&gt;
                    {foreach from=$bibliographies item=bibliography}
                        &lt;option value=&quot;{$bibliography-&gt;getURL(&apos;-action=edit&apos;)}&quot;&gt;
                            {$bibliography-&gt;getTitle()}
                        &lt;/option&gt;
                    
                    {/foreach}
                &lt;/select&gt;
                &lt;/li&gt;
                &lt;li&gt;&lt;img src=&quot;{$ENV.DATAFACE_URL}/images/file.gif&quot;/&gt; 
                    Embed your bibliography in a webpage:
                    &lt;select onchange=&quot;window.location.href=this.options[this.selectedIndex].value&quot;&gt;
                    &lt;option value=&quot;&quot;&gt;Select ...&lt;/option&gt;
                    {foreach from=$bibliographies item=bibliography}
                        &lt;option value=&quot;{$bibliography-&gt;getURL(&apos;-action=view&apos;)}#embed&quot;&gt;
                            {$bibliography-&gt;getTitle()}
                        &lt;/option&gt;
                    
                {/foreach}
                &lt;/select&gt;
                &lt;/li&gt;
                
            &lt;/ul&gt;
    {/fill_slot}
{/use_macro}
&lt;/code&gt;

A few key things to notice in this template:

# It extends the &apos;&apos;Dataface_Main_Template.html&apos;&apos; template placing its content in the &apos;&apos;main_column&apos;&apos; slot.  This allows our action to still display within the header and footer of our application.
# It makes use of the {$ENV.DATAFACE_SITE_URL} and {$ENV.DATAFACE_SITE_HREF} variables to refer to the site&apos;s base url and create links to the desired common actions.
# It provides a direct link to the &apos;&apos;new bibliography record&apos;&apos; form.
# It uses some slick javascript combined with select lists to allow the user to select any of his current bibliogaphies and edit them, or embed them into a webpage.

====Adding entry to the actions.ini file====

Currently our dashboard action has no permissions attached to it so users can see it whether they are logged in or not.  In this particular application we want to require users to log in, and we have set permissions for all logged in users to NO_ACCESS().  Unfortunately this permission setting is only helpful if our action requires a particular permission to access it.  We&apos;ll require the &apos;view&apos; permission for this action, by adding the following to the actions.ini file:

&lt;code&gt;
[dashboard]
    permission=view
&lt;/code&gt;


===Step 4: Specify permissions===

We still want to specify permissions for our &apos;&apos;dashboard&apos;&apos; table to ensure that only logged in users can access the dashboard.  So we create a delegate class for the &apos;&apos;dashboard&apos;&apos; table at &apos;&apos;tables/dashboard/dashboard.php&apos;&apos; with the following contents:

&lt;code&gt;
&lt;?php
class tables_dashboard {
    function getPermissions(&amp;$record){
        if ( getUser() ){
            return Dataface_PermissionsTool::ALL();
        }
        return null;
    }
}
&lt;/code&gt;

&apos;&apos;&apos;Note that we have defined the getUser() function elsewhere as a means of obtaining the current user and checking if a user is indeed logged in.&apos;&apos;&apos;

Notice that this [[getPermissions]] method returns all permissions only if the user is logged in.  Otherwise it returns null, which means that it should use the same permissions as the rest of the application as defined in the [[Application Delegate Class]].

===Step 6: Make &apos;&apos;dashboard&apos;&apos; the default action for the &apos;&apos;dashboard&apos;&apos; table===

Now we just have one more detail that needs to be taken care of.  We want the &apos;&apos;dashboard&apos;&apos; action to be the default action for the &apos;&apos;dashboard&apos;&apos; table only.  By default we would see the &apos;&apos;list&apos;&apos; action which isn&apos;t helpful at all, so we will want to add a rule in our application delegate class to ensure that the user only sees our custom &apos;&apos;dashboard&apos;&apos; action if they access the &apos;&apos;dashboard&apos;&apos; table.  We define a beforeHandleRequest() method in our conf/ApplicationDelegate.php (the application delegate class) file for this purpose:

&lt;code&gt;
&lt;?php
class conf_ApplicationDelegate {
    
...
    function beforeHandleRequest(){
        ...
        $app =&amp; Dataface_Application::getInstance();
	$query =&amp; $app-&gt;getQuery();
	if ( $query[&apos;-table&apos;] == &apos;dashboard&apos; and ($query[&apos;-action&apos;] == &apos;browse&apos; or $query[&apos;-action&apos;] == &apos;list&apos;) ){
	    $query[&apos;-action&apos;] = &apos;dashboard&apos;;
	}
        
        
    }
    
    ...
}
&lt;/code&gt;

This simply checks to see if the table is &apos;&apos;dashboard&apos;&apos; and changes the current action to &apos;&apos;dashboard&apos;&apos; if so.

===Step 7: Try it out===

At this point, we are ready to try out our new dashboard to see how it works.  When we load our application it should now go to the dashboard action that we created.  We should also see &apos;&apos;Dashboard&apos;&apos; listed as the first table in the tables menu.

This dashboard presents a major improvement to our application as it is now much more user friendly.

&lt;nowiki&gt;
&lt;img src=&quot;http://media.weblite.ca/files/photos/pub-dashboard.png?max_width=640&quot;/&gt;
&lt;/nowiki&gt;</content>
	<keywords>dashboard</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=82">
	<page_name>Creating_Printable_Reports</page_name>
	<page_id>82</page_id>
	<page_title>Creating a Custom Printable Report</page_title>
	<content>==Creating a Printable Report==

[[toc]]

It is often useful to provide your users with a printable report that is generated from your database.  Although Xataface doesn&apos;t include an explicit reporting module to allow the end users to create their own reports, you (the developer) can still quite easily produce a report by creating a custom action.  

This report will be subject to the user&apos;s sorting and searching preferences.  E.g. if the user searches for only books about &quot;frogs&quot;, then when he clicks on your printable report it will only display those records that match the query (i.e. only books about frogs).

===Requirements for our report===

# Report will be run against the &quot;products&quot; table (using the WebAuction application).
# Report should be accessible by clicking an icon in the top right of the list view (i.e. the resultlist actions).
# Report should display the product ID, product name, photo, and description.  One product per page.


===Adding the Icon to our Application===

We&apos;ll start out by finding an appropriate icon to use for our action.  There are loads of free icons that you can download (please observe and respect the license agreement of any icon library that you use).  Two good free icon libraries include:

# [http://www.famfamfam.com/lab/icons/silk/ FamFamFam Silk Icons]
# [http://tango.freedesktop.org/Tango_Icon_Library Tango Icon Library]

Once you have found the icon you want to use, just upload it somewhere inside your application&apos;s directory.  It might be a good idea to create a directory to store your images if you haven&apos;t already.  An appropriate name might by &apos;&apos;images&apos;&apos;.  For this example, we&apos;ll use the [[Image:http://dev.weblite.ca/phpimageserver/photos/icons/printer.png]] icon from the FamFamFam icon library.  So we upload this icon to
 %APPLICATION_PATH%/images/printer.png

Next we need to create an entry in our application&apos;s [[actions.ini file]] so that Xataface knows about our action, and where we want its icon to be displayed.  We&apos;ll start out with a basic definition that just specifies the icon for the action, and the &apos;&apos;category&apos;&apos; of the action.

&lt;code&gt;
[printable_report]
    icon=&quot;{$site_url}/images/printer.png&quot;
    category=result_list_actions
    description=&quot;See this product list in a printable format&quot;
&lt;/code&gt;

The &apos;&apos;result_list_actions&apos;&apos; category setting means that the icon for our action will be included along with the result list actions, which are located in the top right corner in the list tab.  Now if we reload our application and look at the &quot;list&quot; tab, you&apos;ll see that the icon group in the top right now includes our icon:

[[Image:http://media.weblite.ca/files/photos/Picture%20-5.png?max_width=640]]

If you don&apos;t see this icon, but see the text &quot;printable_report&quot; instead, then you have entered an incorrect path to the icon in the &apos;&apos;icon&apos;&apos; directive.  If you don&apos;t see an icon at all or any text, then your &apos;&apos;category&apos;&apos; directive may be incorrect.  Check that it is exactly &quot;result_list_actions&quot;.

If you mouse over your icon you&apos;ll see the text that you specified as your &apos;&apos;description&apos;&apos; directive for the action:

[[Image:http://media.weblite.ca/files/photos/Picture%20-6.png?max_width=640]]

You&apos;ll notice, if you try to click on your icon, that nothing happens.  This is because we haven&apos;t yet specified a URL for your action.  We&apos;ll wait to specify our URL, until we&apos;ve built the back-end of our action (i.e. the actual report).

===Creating the Actual Report===

Most reports involve the following pieces:

# Fetch the found set of records from the database.
# Loop through the found set and output some information about each record.
# Optionally use a template to integrate the report into your application&apos;s look and feel.

All reports will be placed in the framework of a custom Xataface action.  In our case we add a file to our application &apos;&apos;actions&apos;&apos; directory named after our action:
 %APPLICATION_PATH%/actions/printable_report.php

with the following contents:

&lt;code&gt;
&lt;?php
class actions_printable_report {
    function handle(&amp;$params){
    	echo &quot;Hello world!!!&quot;;
    }
}
&lt;/code&gt;

Please note the following about this snippet:

# The action was placed in a file &apos;&apos;actions/printable_report.php&apos;&apos; because the action is named &apos;&apos;printable_report&apos;&apos; (referring to our definition in the &apos;&apos;[[actions.ini file]]&apos;&apos;.  If the action was named &apos;&apos;foo&apos;&apos;, then we would place our action in file &apos;&apos;actions/foo.php&apos;&apos;.
# The &apos;&apos;printable_report.php&apos;&apos; file contains a single class named &apos;&apos;actions_printable_report&apos;&apos; after the name of the action.
# The action class contains a single method &apos;&apos;handle&apos;&apos; which handles the request for the action (i.e. outputs the report the way we like).  This method must exist and me named exactly &apos;&apos;handle&apos;&apos;.
# The &apos;&apos;handle&apos;&apos; method takes a single &apos;&apos;&amp;$params&apos;&apos; parameter which contains some parameters that may be passed to the action.  We won&apos;t be dealing with these in this example.


Before proceeding, let&apos;s try accessing our action just to make sure that we&apos;re on the right track.  Point your browser to 
 http://example.com/yourapplication/index.php?-action=printable_report

Note that you don&apos;t point our web browser directly to your action php file (in the &apos;&apos;actions&apos;&apos; directory.  Rather you point it to your application&apos;s entry point (index.php file), and specify the action via the &apos;&apos;-action&apos;&apos; GET parameter.  Your web browser should display something like:

[[Image:http://media.weblite.ca/files/photos/Picture%204.png?max_width=640]]

If you get a blank white screen, then you should check your error log to see where the error is occuring.  See [[Troubleshooting]] for general Xataface troubleshooting strategies in this case.

Now that we have all of the formalities out of the way, we can proceed to meat of our report.

====Retrieving the Found Set====

Let&apos;s build onto our action now.  First we will load the found set of records as follows:

&lt;code&gt;
&lt;?php
class actions_printable_report {
    function handle(&amp;$params){
    	$app =&amp; Dataface_Application::getInstance();
    	$query =&amp; $app-&gt;getQuery();
    	
    	if ( $query[&apos;-table&apos;] != &apos;products&apos; ){
    		return PEAR::raiseError(&apos;This action can only be called on the Products table.&apos;);
    	}
    	
    	$products = df_get_records_array(&apos;products&apos;, $query);
    	
    }
}
&lt;/code&gt;

Things to note in this snippet:

# We start be loading a reference to the &apos;&apos;Dataface_Application&apos;&apos; object.
# We then use the &apos;&apos;Dataface_Application&apos;&apos; object to load the current query.  This is essentially an associative array of all of the GET parameters, but with some guaranteed attributes such as &apos;&apos;-table&apos;&apos; and &apos;&apos;-action&apos;&apos;.
# In our particular action we are designing it to only work for the &apos;&apos;products&apos;&apos; table so we do a check on the query parameters to make sure that this is the case.  If someone tries to run this action from outside the products table (e.g. if -action=foo) then an error will be displayed.
# We use the df_get_records_array() function to return all matching records on the products table.  It returns an array of [[Dataface_Record]] objects.


====Overriding -skip and -limit====

Xataface allows the user to specify the number of records to display and the position in the found set to start from by adding the &apos;&apos;-skip&apos;&apos; and &apos;&apos;-limit&apos;&apos; GET parameters to a request.  If these are omitted, then default values of 0 and 30 are used respectively.  You may notice that if you click &quot;Next&quot; in list view, you see &apos;-skip&apos; and &apos;-limit&apos; parameters automatically added to the URL.

&apos;&apos;df_get_records_array&apos;&apos; respects the -limit and -skip parameters that are specified in the query.  I.e. if -skip and -limit are omitted it will return only the first 30 records from the found set.  If -skip=1 and -limit=10 then it will return 10 records starting from the 2nd record (2nd becuase -skip=0 would point to the first record).  This may be desired behavior for your report, but in some reports you may want to print off the entire found set.  If this is the case, you will want to explicitly set the -skip and -limit parameters in the &apos;&apos;$query&apos;&apos; array before passing it to &apos;&apos;df_get_records_array&apos;&apos;.  E.g.:

&lt;code&gt;
$query =&amp; $app-&gt;getQuery();
$query[&apos;-skip&apos;] = 0;
$query[&apos;-limit&apos;] = 10000;
$products = df_get_records_array(&apos;products&apos;, $query);
&lt;/code&gt;


====Looping through and Printing Product Info====

Now comes the fun part.  We&apos;re just going to loop through our found set and print off the product information:

&lt;code&gt;


foreach ($products as $p){
	

	echo &apos;&lt;table&gt;&apos;
		.&apos;&lt;tr&gt;&lt;th&gt;Product ID&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_id&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
		.&apos;&lt;tr&gt;&lt;th&gt;Product Name&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_name&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
		.&apos;&lt;tr&gt;&lt;th&gt;Description&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_description&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
		.&apos;&lt;tr&gt;&lt;th&gt;Photo&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_image&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
		.&apos;&lt;/table&gt;&apos;;
}

&lt;/code&gt;


The entire action at this point will look like:

&lt;code&gt;

&lt;?php
class actions_printable_report {
    function handle(&amp;$params){
    	$app =&amp; Dataface_Application::getInstance();
    	$query =&amp; $app-&gt;getQuery();
    	$query[&apos;-skip&apos;] = 0;
		$query[&apos;-limit&apos;] = 10000;
		
    	if ( $query[&apos;-table&apos;] != &apos;products&apos; ){
    		return PEAR::raiseError(&apos;This action can only be called on the Products table.&apos;);
    	}
    	
    	$products = df_get_records_array(&apos;products&apos;, $query);
    	foreach ($products as $p){
	

			echo &apos;&lt;table&gt;&apos;
				.&apos;&lt;tr&gt;&lt;th&gt;Product ID&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_id&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
				.&apos;&lt;tr&gt;&lt;th&gt;Product Name&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_name&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
				.&apos;&lt;tr&gt;&lt;th&gt;Description&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_description&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
				.&apos;&lt;tr&gt;&lt;th&gt;Photo&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_image&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
				.&apos;&lt;/table&gt;&apos;;
		}
    	
    }
}
&lt;/code&gt;

Now we refresh our action in the web browser, or point the browser again to:
 http://example.com/yourapplication/index.php?-action=printable_report&amp;-table=products
 
It should display something like:

[[Image:http://media.weblite.ca/files/photos/Picture%205.png?max_width=640]]

If you get a blank white screen, please check out the [[Troubleshooting]] section for general Xataface troubleshooting strategies.

====Adding a Little Style====

It is a good idea to at least provide the proper HTML HEAD and BODY tags for your report.  And to help make things a little nicer looking we&apos;re going to add some CSS styles to:

# Make the table field labels vertically aligned to the top.
# Change the font to helvetica.

This is easy to do with simple echo statements:

&lt;code&gt;
echo &apos;&lt;html&gt;&lt;head&gt;&apos;
	.&apos;&lt;title&gt;Printable Report&lt;/title&gt;&apos;
	.&apos;&lt;style type=&quot;text/css&quot;&gt;&apos;
	.&apos;	th { vertical-align: top}&apos;
	.&apos;&lt;/style&gt;&apos;
	.&apos;&lt;/head&gt;&apos;
	.&apos;&lt;body&gt;&apos;;
	
	//...
	


&lt;/code&gt;

So our finished action looks like:


&lt;code&gt;
&lt;?php
class actions_printable_report {
    function handle(&amp;$params){
    	$app =&amp; Dataface_Application::getInstance();
    	$query =&amp; $app-&gt;getQuery();
    	$query[&apos;-skip&apos;] = 0;
		$query[&apos;-limit&apos;] = 10000;
		
    	if ( $query[&apos;-table&apos;] != &apos;products&apos; ){
    		return PEAR::raiseError(&apos;This action can only be called on the Products table.&apos;);
    	}
    	
    	$products = df_get_records_array(&apos;products&apos;, $query);
    	
    	
    	
    	echo &apos;&lt;html&gt;&lt;head&gt;&apos;
			.&apos;&lt;title&gt;Printable Report&lt;/title&gt;&apos;
			.&apos;&lt;style type=&quot;text/css&quot;&gt;&apos;
			.&apos;	th { vertical-align: top}&apos;
			.&apos;&lt;/style&gt;&apos;
			.&apos;&lt;/head&gt;&apos;
			.&apos;&lt;body&gt;&apos;;
    	foreach ($products as $p){
	

			echo &apos;&lt;table&gt;&apos;
				.&apos;&lt;tr&gt;&lt;th&gt;Product ID&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_id&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
				.&apos;&lt;tr&gt;&lt;th&gt;Product Name&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_name&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
				.&apos;&lt;tr&gt;&lt;th&gt;Description&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_description&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
				.&apos;&lt;tr&gt;&lt;th&gt;Photo&lt;/th&gt;&lt;td&gt;&apos;.$p-&gt;htmlValue(&apos;product_image&apos;).&apos;&lt;/td&gt;&lt;/tr&gt;&apos;
				.&apos;&lt;/table&gt;&apos;;
		}
		
		echo &apos;&lt;/body&gt;&lt;/html&gt;&apos;;
    	
    }
}
&lt;/code&gt;



===Connecting the Icon to the Action===

FInally it is time to connect our Icon to our Action.  We do this by adding a &apos;&apos;url&apos;&apos; directive for the action in the &apos;&apos;[[actions.ini file]]&apos;&apos;:


&lt;code&gt;
[printable_report]
    icon=&quot;{$site_url}/images/printer.png&quot;
    category=result_list_actions
    description=&quot;See this product list in a printable format&quot;
    url=&quot;{$app-&gt;url(&apos;-action=printable_report&apos;)}&quot;
&lt;/code&gt;

Explanation of the &apos;&apos;url&apos;&apos; directive in this snippet:

* The &apos;&apos;url&apos;&apos; method of the &apos;&apos;[[Dataface_Application]]&apos;&apos; object is used to generate a URL with the user&apos;s current query settings, but with the &apos;&apos;-action&apos;&apos; parameter set to &apos;&apos;printable_report&apos;&apos;.

Now if we reload our application, go to the list tab of the &apos;&apos;products&apos;&apos; table and click on our icon, it should take us to our action:

[[Image:http://media.weblite.ca/files/photos/Picture%207.png?max_width=640]]

===Trying out the action on different found sets with different sort orders===

One of the cool things about this action is that it is tied directly into the Xataface find settings so that th user is able to search for a subset of products and run our report on only those products that were found.  The user can also perform a sort on any column and this sort will be respected by our report.

===Hiding Icon from Other Tables===

Since our action is only intended to operate on the &apos;&apos;products&apos;&apos; table it probably isn&apos;t a good idea to make the icon visible for every other table.  For example, if you go to the list view of the &apos;&apos;users&apos;&apos; table, you&apos;ll see the printer icon in the top right just like it appears for the &apos;&apos;products&apos;&apos; table.  Clicking on it should display our error:

[[Image:http://media.weblite.ca/files/photos/Picture%206.png?max_width=640]]

We will use a &apos;&apos;condition&apos;&apos; directive for our action to hide it from tables other than the &apos;&apos;products&apos;&apos; table as follows:

 condition=&quot;$query[&apos;-table&apos;] == &apos;products&apos;&quot;
 
So our action will now look like:

&lt;code&gt;
[printable_report]
    icon=&quot;{$site_url}/images/printer.png&quot;
    category=result_list_actions
    description=&quot;See this product list in a printable format&quot;
    url=&quot;{$app-&gt;url(&apos;-action=printable_report&apos;)}&quot;
    condition=&quot;$query[&apos;-table&apos;] == &apos;products&apos;&quot;
&lt;/code&gt;

Now if you reload the list for the &apos;&apos;users&apos;&apos; table you&apos;ll notice that the printer icon is now gone.  But returning to the &apos;&apos;products&apos;&apos; table shows our action still alive and well.

===Locking Down our Action with Permissions===

In our case we don&apos;t want our action to be accessible to all users.  Only administrators.  Xataface permissions and all its possibilities are beyond the scope of this tutorial, but we still want to demonstrate how to lock down this action.  The WebAuction application into which this action is being installed defines a permission called &apos;&apos;reports&apos;&apos; which only administrators have.  We will use this permission to limit access to this action as follows in the actions.ini file:
 permission=reports

So the actions.ini file will now look like:
&lt;code&gt;
[printable_report]
    icon=&quot;{$site_url}/images/printer.png&quot;
    category=result_list_actions
    description=&quot;See this product list in a printable format&quot;
    url=&quot;{$app-&gt;url(&apos;-action=printable_report&apos;)}&quot;
    condition=&quot;$query[&apos;-table&apos;] == &apos;products&apos;&quot;
    permission=reports
&lt;/code&gt;

Now only administrators will see our icon, and if non-administrators attempt to access out action by typing in its URL directly, they will receive an &quot;Access Denied&quot; message.

</content>
	<keywords></keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=103">
	<page_name>Customizing_Theme_Based_on_IP_Address</page_name>
	<page_id>103</page_id>
	<page_title>Customizing Theme Based on IP Address</page_title>
	<content>This article deals with the following topics:

# Using [[field__pullValue]]/[[field__pushValue]] methods to customize how a field is edited and stored in the database.
# Using [[beforeHandleRequest]] to modify the application settings based on the user&apos;s IP address
# Storing ranges of IP addresses in the database.

Last week I set up a site that needed to have slightly different behavior depending on the IP address of the remote user.  E.g.  If a user is connecting from an IP address between 192.168.0.0 to 192.168.0.255 we would use a different theme than if they were connecting from a different block.  In addition to different themes, we also to use different types of authentication depending on which IP block the user is visiting from.

This requirement is actually common for systems that are syndicated by different organizations and should behave slightly differently depending on which organization the user belongs to (assuming they are connecting from that organization&apos;s network).

To implement this behavior we need to solve one issue.

&apos;&apos;&apos;How do we store a range of IP addresses in the database so that they can be queried easily to match if the user&apos;s IP address falls in that range.&apos;&apos;&apos;
	
It turns out that this is quite easy to do, since IP addresses are actually just a 4 digit number (base 256).  So we can easily convert this number to base 10 and store it as a regular unsigned integer in the database.  In addition, both PHP and MySQL provide functions to convert from an IP address to an integer and back.

The PHP functions are called [http://ca3.php.net/long2ip long2ip] and [http://ca3.php.net/ip2long ip2long] respectively.

So we have stored a start IP address and an end IP address as integers, we could simply query the database to see if a given IP address falls in that range as follows:

&lt;code&gt;
$intIP = ip2long($_SERVER[&apos;REMOTE_ADDR&apos;]);
$sql = sprintf(&apos;select * from ip_blocks where start_ip&lt;=%u and end_ip&gt;=%u&apos;, $intIP, $intIP);
... etc....
&lt;/code&gt;

&apos;&apos;&apos;It is important to note that you need to use the sprintf() function for converting $intIP into a string because PHP will convert it to an integer which could overflow if you leave it to do a default conversion.&apos;&apos;&apos;
	
For the above query, we assuming a table with a definition like:

&lt;code&gt;
create table ip_blocks (
    ip_block_id int(11) not null primary key,
    start_ip unsigned int(11) not null
    end_ip unsigned int(11),
    key (start_ip),
    key (end_ip)
)
&lt;/code&gt;
	
Now if we attach some information to the IP block, like the theme that should be used, we can check the user IP address against the available IP blocks at the beginning of each request to set the theme for that request.  We will use the [[beforeHandleRequest]] method of the [[Application Delegate Class]] to house this because it allows us to set things like the theme or change the user&apos;s action.

e.g.

&lt;code&gt;
class conf_ApplicationDelegate {
	function beforeHandleRequest(){
		$app = Dataface_Application::getInstance();
		
		// Get a reference to the current query so we can
		// alter it if necessary.
		$query =&amp; $app-&gt;getQuery();
		
		
		// Get the user&apos;s IP address and covert it to a long int.
		$intIP = ip2long($_SERVER[&apos;REMOTE_ADDR&apos;]);
		$sql = sprintf(&apos;select `theme` from ip_blocks where start_ip&lt;=%u and end_ip&gt;=%u&apos;, $intIP, $intIP);
		
		$res = mysql_query($sql, df_db());
		if ( !$res ) throw new Exception(mysql_error(df_db()));
		
		$row = mysql_fetch_row($res);
		
		// If we didn&apos;t find any valid IP ranges, let&apos;s redirect the
		// user to a different action to let them know that
		// they&apos;re not welcome here.
		if ( !$row ){
			$query[&apos;-action&apos;] = &apos;not_welcome&apos;;
				// This assumes that we have defined an action
				// called &quot;not_welcome&quot;
				
			return;
		}
		
		$theme = $row[0];
		$themePath = &apos;themes/&apos;.basename($theme);
		// Check that the theme exists.
		if ( $theme and file_exists($themePath) ){
			df_register_skin($theme, $themePath);
		}
	}
}
&lt;/code&gt;

The above snippet makes use of the [[df_register_skin]] method that registers a theme to be used dynamically.  The first parameter is the theme name, and the second parameter is the path to the theme.


This code works great if we already have IP addresses stored properly as integers in our database, but how do we make it so users can work with the IP addresses as IP addresses and not integers?  We need to be able to transform from integer to IP address to display in the edit record form, and then convert the resulting IP address back to an integer for storage in the database.  Xataface provides two delegate class methods precisely for this purpose:

# [[field__pullValue]] - Transforms a value as stored in the database to a format that is preferred in the edit form.
# [[field__pushValue]] - Transforms a value entered into the edit form into a format that is preferred by the database.

So, in our delegate class we would have:

&lt;code&gt;
&lt;?php
class tables_ip_blocks {

	/**
	 * @param Dataface_Record $record The record we are pushing the value
	 *		into
	 * @param HTML_QuickForm_element $el The QuickForm widget that we are 
	 *      retrieving the value from.
	 */
	function start_ip__pushValue($record, $el){
		$val = ip2long($el-&gt;getValue());
		if ( $val !== false ){
			return sprintf(&apos;%u&apos;, $val );
		}
		return null;
	}
	
	function start_ip__pullValue($record, $el){
		$val = $record-&gt;val(&apos;start_ip&apos;);
		if ( $val )
			return long2ip($val);
		return $val;
	}
	
	function end_ip__pushValue($record, $el){
		$val = ip2long($el-&gt;getValue());
		if ( $val !== false ){
			return sprintf(&apos;%u&apos;, $val );
		}
		return null;
	}
	
	function end_ip__pullValue($record, $el){
		$val = $record-&gt;val(&apos;end_ip&apos;);
		if ($val){
			return long2ip($val);
		}
		return $val;
	}
	
	
}
&lt;/code&gt;

The [[field__pullValue]] and [[field__pushValue]] method should be inverses of each other.

&apos;&apos;&apos;Note that support for [[field__pullValue]] and [[field__pushValue]] are supported by Xataface since version 0.6, however support for them with the grid widget was not added until Xataface version 1.3.&apos;&apos;&apos;
	

Now, on the edit form, users can enter and edit IP addresses in the normal format, but they will be converted to unsigned integers for storage in the database.

There is only one thing remaining, though.  In the list view still shows the integer version of the IP addresses. We want them to show them as regular IP addresses.  So we add [[field__display]] methods to our delegate class:

&lt;code&gt;
function start_ip__display($record){
	$val = $record-&gt;val(&apos;start_ip&apos;);
	if ( $val )
		return long2ip($val);
	return $val;
}

function end_ip__display($record){
	$val = $record-&gt;val(&apos;end_ip&apos;);
	if ($val){
		return long2ip($val);
	}
	return $val;
}
&lt;/code&gt;

==References==

* [http://xataface.com/documentation/how-to/how-to-define-custom-serialization-for-fields How to define custom serialization for fields]
</content>
	<keywords>ip address, pullValue, pushValue, beforeHandleRequest</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki></record>