page_name,page_id,page_title,content,keywords,language,original_page
modules,30,"Xataface Modules","[[toc]]

Xataface provides a number of hooks that allow developers to create modules to extend its functionality.  This page lists a handful of the currently available modules.

* [[ShoppingCart|Shopping Cart]] - Converts your application into a shopping cart.
* [[Filemaker]] - Export record sets as Filemaker XML.
* [[DataGrid|Data Grid]] - Editable Datagrid.
* [[Email]] - Convert your database into a email list.  Send email to any found set.
* [[reCAPTCHA module]] - A reCAPTCHA module to add CAPTCHA support to your Xataface forms.
* [[XataJax]] - Platform for building Web 2.0 AJAX applications with Xataface.  Will be a standard component for Xataface starting with version 1.3.

==Module Installation==

You can add modules in either:

# DATAFACE_PATH/modules directory (since 1.0)
# DATAFACE_SITE_PATH/modules directory (since 1.3)

Modules in the DATAFACE_SITE_PATH directory will supersede modules in the DATAFACE_PATH/modules directory (since 1.3).

To activate a module for your application you also need to add an entry to the [[_modules]] section of your [[conf.ini file]].  Each module will come with its own installation instructions.

==Authentication Modules==

Modules to add alternative authentication methods are added to the modules/Auth directory.

==Developing Your Own Modules==

See [[Module Developers Guide]].","modules, captcha",en,0
ShoppingCart,31,ShoppingCart,"==Xataface Shopping Cart Module==

[[toc]]

Status: Under development
Current Version: 0.2

===Synopsis===

Add a shopping cart to your xataface application.  You can treat any record as a product that can be sold.  Includes Paypal connectivity, shipping calculation, and more.

===Requirements===

* Xataface 1.0 or higher
* PHP 5 or higher
* MySQL 4.1 or higher

===Installation Instructions===

# Download the ShoppingCart module, extract it, and place the ShoppingCart directory in your Xataface modules directory. (i.e. /path/to/xataface/modules/ShoppingCart).
# Add the following line to the [_modules] section of your [[conf.ini file]]:<code>
modules_ShoppingCart=modules/ShoppingCart/ShoppingCart.php
</code>
# Add the following to the beginning of your [[index.php file]]:<code>
function __autoload($class){
    if ( $class == 'ShoppingCart' ) require_once 'modules/ShoppingCart/lib/ShoppingCart/ShoppingCart.class.php';
}
</code>
# In the [[fields.ini file]] for any table whose records you wish to represent items for sale, add the following:<code>
[__implements__]
    InventoryItem=1
</code>
# Specify which fields should be used for the item description, price, width, height, length, and weight in the [[fields.ini file]] for each table whose records you wish to represent items for sale by adding the following directives to the appropriate fields:<code>
ShoppingCart.description=1
ShoppingCart.unitPrice=1
ShoppingCart.weight=1
ShoppingCart.width=1
ShoppingCart.height=1
ShoppingCart.length=1
</code> E.g. if your table has a field named """"price"""" that you want to represent the unit price, you would have something like:<code>
[price]
    ShoppingCart.unitPrice=1
</code>  The shopping cart module will make its best guess on which fields to use for these values if they are not explicitly specified.
# Specify the paypal account where money should be deposited by adding the following to your application's [[actions.ini file]]:<code>
[view_cart]
    paypal.account=""youremail@example.com""
</code>


===Usage Instructions===

Once the Shopping Cart module is installed you can:

# Add items to your shopping cart
# View your cart contents
# Checkout and pay with paypal

====Adding Items to the Cart====

In the View tab of any salable record, you'll notice a little block on the left side of the page with the heading ""Add Item to Cart"".  This includes a field to specify the quantity and a button to add the item to the shopping cart.

====Viewing Cart Contents====

The Shopping Cart module automatically introduces an action to view the cart contents.  This action is named ""view_cart"".  Hence you can always view the cart contents by entering the URL: index.php?-action=view_cart .

====Checking Out====

# View the cart contents.
# Click ""Check out""
# This will take you to a paypal page to pay for your items.


==Actions==

This module adds the following actions to your application.

{| class=""listing listing2""
|-
! Name
! Content-type
! Description
! Version
|-
| checkout
| text/html
| Sends user to paypal to pay for the contents of their cart.
| 0.1
|-
| calculate_shipping
| text/html
| Calculates the shipping charges for the cart.
| 0.1
|-
| add_to_cart
| text/html
| Adds an item to the cart.
| 0.1
|-
| clear_cart
| text/html
| Empties the shopping cart.
| 0.1
|-
| get_shipping_provinces
| text/json
| Returns JSON array of provinces for a given country.
| 0.1
|-
| invoices
| text/html
| Displays the current user's invoices.
| 0.1
|-
| payment_complete
| text/html
| Page that is displayed after a successful payment on paypal.
| 0.1
|-
| paypal_ipn
| none
| Handles paypal events such as successful payments.
| 0.1
|-
| refresh_shipping_methods
| text/html
| Refreshes the shipping methods available to the system.
| 0.1
|-
| set_shipping_method
| text/html
| Sets the selected shipping method to a particular method.
| 0.1
|- 
| view_cart
| text/html
| View the cart contents.
| 0.1
|}

==Blocks and Slots==

This module adds the following blocks and slots to your applications.

{| class=""listing listing2""
|-
! Name
! Description
! Version
|-
| shipping_method
| A block with a form to select the shipping method.
| 0.1
|-
| add_to_cart
| A block with a form to add a record/item to the shopping cart.
| 0.1 
|}

==Application Delegate Class Hooks==

You can modify the shopping cart behavior by defining the following methods to the application delegate class.

{| class=""listing listing2""
|-
! Name
! Description
! Version
|-
| isShippingMandatory
| Returns a boolean value indicating whether the user must select a shipping method.
| 0.1
|-
| getDefaultShippingMethod
| Returns a string with the name of the default shipping method to be used.
| 0.1
|}


==Table Delegate Class Hooks==

You can modify the behavior of the shopping cart by defining the following methods to the delegate class of any table that implements the InventoryItem ontology (i.e. any table that is to be used to store products that can be added to the cart).

{| class=""listing listing2""
|-
! Name
! Description
! Version
|-
| field__taxes
| A calculated field that returns an associative array of all applicable taxes for a product.
| 0.1
|}

==Internal Storage==

This module creates the following tables to store its data:

===dataface__invoices===

The dataface__invoices table stores the actual invoices for purchases made.  An invoice is automatically created as soon as the user ""checks out"".

{| class=""listing listing2""
|-
! Column Name
! Data Type
! Description
! Version
|-
| InvoiceID
| int(11)
| Auto incrementing primary key for the invoice.
| 0.1
|-
| dateCreated
| datetime
| The date that the invoice was created.
| 0.1
|-
| dateModified
| datetime
| The date that the invoice was last modified
| 0.1
|-
| status
| enum
| The status of the invoice (either PENDING, PAID, or APPROVED).
| 0.1
|-
| amount
| decimal(10,2)
| The total amount on the invoice.
| 0.1
|-
| paymentMethod
| varchar(32)
| The name of the payment method used.
| 0.1
|-
| referenceID
| varchar(64)
| ??
| 0.1
|-
| username
| varchar(32)
| The username of the user who owns this invoice.
| 0.1
|-
| firstName
| varchar(32)
| The first name of the payer.
| 0.1
|-
| lastName
| varchar(32)
| The last name of the payer.
| 0.1
|-
| address_name
| varchar(100)
| The name on the shipping address.
| 0.1
|-
| address1
| varchar(100)
| The shipping address line 1.
| 0.1
|-
| address2
| varchar(100)
| The shipping address line 2.
| 0.1
|-
| city
| varchar(40)
| The shipping address city.
| 0.1
|-
| province
| varchar(2)
| The shipping province or state.
| 0.1
|-
| country
| varchar(2)
| The shipping country.
| 0.1
|-
| postalCode
| varchar(32)
| The shipping postal code.
| 0.1
|-
| shipping_method
| varchar(50)
| The name of the shipping method to use.
| 0.1
|-
| phone
| varchar(32)
| The phone number of the payer.
| 0.1
|-
| email
| varchar(127)
| The email address of the buyer.
| 0.1
|-
| data
| text
| Serialize shopping cart data.
| 0.1
|}


===dataface__shipping_methods===

Stores the available shipping methods.

{| class=""listing listing2""
|-
! Column Name
! Data Type
! Description
! Version
|-
| shipping_method_id
| int(11)
| Auto increment ID for a shipping method.
| 0.1
|-
| shipping_method_name
| varchar(50)
| The name of the shipping method.
| 0.1
|-
| shipping_method_label
| varchar(100)
| The label for the shipping method (displayed to the user).
| 0.1
|-
| shipping_method_enabled
| tinyint(1)
| Whether or not this shipping method is currently enabled.
| 0.1
|-
| shipping_method_module
| varchar(32)
| The name of the handler that this shipping method belongs to.
| 0.1
|}

==Payment Handlers==

Information about payment handlers to be added here.

==Shipping Handlers==

The Shopping Cart module is itself modular, allowing you to develop custom shipping handlers for different types of shipping.  A shipping handler is responsible for calculating shipping costs to a destination address.  Currently only a UPS shipping handler has been created, but it is not difficult to create other handlers.

===Shipping Handler Public Interface===

{| class=""listing listing2""
|-
! Method
! Description
! Version
|-
| calculateShipping
| Calculates the shipping cost for the current shopping cart, and adds the shipping cost to the cart as a line item.
| 0.1
|-
| getInfo
| Returns an array of shipping methods that can be handled by this handler.
| 0.1
|}






",,en,0
DataGrid,32,DataGrid,"==Xataface DataGrid Module==

Created by Steve Hannah, [http://weblite.ca Web Lite Solutions Corp.]

===Synopsis===

The Xataface DataGrid module uses the Ext DataGrid component (http://extjs.com) to add an editable grid component to your Xataface application.

[[toc collapse=0]]

===Requirements===

* PHP 4.3+
* MySQL 4.1+
* Xataface 0.8+

===License===

This module is distributed with ExtJS 2.2, which is distributed under the GPL v 3 (http://extjs.com/products/license.php).

In order to be compatible with the ExtJS license, this module is also distributed under the terms of the GPL v3 (http://www.gnu.org/copyleft/gpl.html).

===Demo Video===

<nowiki>
<embed src=""http://media.weblite.ca/lib/flvplayer.swf"" width=""640"" height=""500"" bgcolor=""#FFFFFF"" type=""application/x-shockwave-flash"" pluginspage=""http://www.macromedia.com/go/getflashplayer"" flashvars=""file=http%3A%2F%2Fs3.amazonaws.com%2Fweblite_media%2FDataGrid-640x480.flv&image=http%3A%2F%2Fmedia.weblite.ca%2Ffiles%2Fphotos%2FDataGrid-640x480.flv.jpg&showdigits=true&autostart=false"" />
</nowiki>

===Screenshots===

Click on image to enlarge

<nowiki>
<script language=""javascript"" type=""text/javascript"" src=""http://media.weblite.ca/index.php?-action=gallery&-table=files&categories=8&-cursor=0&-skip=0&-limit=30&-mode=list&-photo_max_width=640&--format=js""></script>

<div style=""clear:both"">&nbsp;</div>
</nowiki>


===Demo===

# LibrarianDB Demo: http://demo.weblite.ca/apps/librariandb/index.php?-table=books&-action=DataGrid_view , '''Log in with username ""admin"" and password ""password""'''

===Download===

* [https://sourceforge.net/project/platformdownload.php?group_id=250381 DataGrid-0.2]
* SVN Repository: http://weblite.ca/svn/dataface/modules/DataGrid

===Installation===

# Download and extract the DataGrid directory into your xataface/modules directory.
# Add the following line to the [_modules] section of your application's [[conf.ini file]]:<code>
modules_DataGrid=modules/DataGrid/DataGrid.php
</code>
# Ensure that your [[permissions]] are set up appropriately to allow your users to access the grid action (see next section).

===Setting Up Permissions===

This module defines the following [[permissions]]:

* DataGrid:view_grid  	- Permission to view the data grid for a table.
* DataGrid:create_grid	- Permission to create a new data grid
* DataGrid:edit_grid		- Permission to edit an existing data grid
* DataGrid:update			- Permission to update records via the grid
* DataGrid:manage_grids	- Permission to access the datagrid control panel

In order for a user to access/use the grid he must be granted at least the Datagrid:view_grid and DataGrid:update [[permissions]].  Both of these [[permissions]] are included in the following system roles by default:

* EDIT
* EDIT AND DELETE
* DELETE
* ADMIN
* MANAGER

And of course these [[permissions]] are included with the call to Dataface_PermissionsTool::ALL() .

If you have assigned your own custom roles and want to enable access to the grid, you can simply add the following to your role definition in your [[permissions.ini file]]:
<code>
[MY ROLE]
    DataGrid:view_grid=1
    DataGrid:update=1
</code>

If you want to explicitly disable the grid for a role, you can extend the role and deny those same [[permissions]]:
<code>
[MY ROLE extends MY ROLE]
	DataGrid:view_grid=0
	DataGrid:update=0
</code>

	
===Usage===

Once installed, log in as a user that has permission to access the grid. You should notice a new tab along with ""details"", ""list"", and ""find"", called ""grid"". Click on the ""grid"" tab to access the grid.

You can double click on any field to edit it.  Modified fields will be marked in red, and automatically saved every 5 seconds - after the changes are saved the field is no longer marked in red.

===Limitations===

Currently only fields with the following widget types are available to be edited in the grid:

# text
# textarea
# select
# date/datetime/time

Other types of fields will simply not be included in the grid.

===Support/Questions===

Visit the Xataface forum at http://xataface.com/forum
	

",,en,0
after_action_new,33,after_action_new,"==after_action_new trigger==

[[toc]]

This trigger is called after the '''new''' 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 'new' action has been successfully completed.  i.e. a maximum of once per request.

===Signature===

<code>
function after_action_new($params=array()){ ... } : return void
</code>

====Parameters====

This method takes a single associative array as a parameter. This array includes the following keys:

* '''record''' - 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====

<code>
function after_action_new($params=array()){
    $record =& $params['record'];
    header('Location: '.$record->getURL('-action=view').'&--msg='.urlencode('Record successfully inserted.'));
    exit;
}
</code>
",,en,0
examples,34,examples,"==Xataface Examples==

[[toc]]

This section includes concrete examples of how Xataface has been used in the past.

===Demo Applications===

{| class=""listing listing2""
|-
! Screenshot
! Title/Description
! Developed by
|-
| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://demo.weblite.ca/apps/librariandb/]]
| '''Librarian DB'''

A searchable database of library books.  Useful for small libraries (e.g. Church Libraries).

Log in with:
username: admin
password: password

[http://demo.weblite.ca/apps/librariandb/ Try the app]
| [http://solutions.weblite.ca Web Lite Solutions Corp.]

|-
| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://demo.weblite.ca/apps/webauction/]]
| '''Web Auction'''

A simple web-based auction application for organizations to hold auctions.

Login with:
username: admin
password: password

[http://demo.weblite.ca/apps/webauction/ Try the app]
| [http://solutions.weblite.ca Web Lite Solutions Corp.]


|}

===Websites Powered by Xataface===

{| class=""listing listing2""
|-
! Screenshot
! Title/Description
! Developed by
|-
| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://fueleconomydb.com]]
| '''Fuel Economy Database''' - A searchable database of gas mileage and fuel economy statistics for automobiles from 1986 to present.

[http://fueleconomydb.com Visit the site]
| [http://solutions.weblite.ca Web Lite Solutions Corp.]
|-
| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://physics.sfu.ca]]
| '''Department of Physics, Simon Fraser University'''
This website is completely powered by Xataface.  It is backed by a MySQL database that stores faculty members, research groups, news, events, and more.  Faculty members are able to update their personal profiles and research profiles through a Xataface administration console.

[http://physics.sfu.ca Visit the site]
| [http://fas.sfu.ca/ SFU Faculty of Applied Sciences]

|-
| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://science.ca]]
| '''Science.ca'''

The source for science in Canada.  Includes profiles for prominent scientists as well as other useful science-related information.  Xataface is used to power the bilingual (English/French) capabilities of this site.  It includes web-based administrative console for the administrator to manage all content, and for translators to translate the content.

[http://science.ca Visit the site]
| Science.ca web team

|-

| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://translation.weblite.ca]]
| '''Simple Website Translation Engine'''

A service that allows website owners to easily convert their website into multiple languages.  Support human and machine translation.  This service is powered by Xataface, and provides an administrative console for users to manage their website translations.

[http://translation.weblite.ca Visit the Site]

[http://swete.weblite.ca More about this service]

| [http://translation.weblite.ca Web Lite Translation Corp.]

|-
| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://www.credituniondb.com]]
| '''Credit Union Database'''

A database of credit unions in the United States.  This site is powered by Xataface.

[http://www.credituniondb.com Visit the site]

| Vlad

|-
| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://ierg.net/lessonplans/unit_plans.php]]
| '''IERG Lesson Plans Database'''

A searchable database of lesson plans created by the Imaginative Education Research Group.  This database is managed by Xataface.  It provides researchers with a web-based control panel to manage their lesson plans.

[http://ierg.net/lessonplans/unit_plans.php Visit the site]

| [http://solutions.weblite.ca Web Lite Solutions Corp.]

|-
| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://ierg.net/people/]]
| '''IERG People Database'''

A simple database to manage the contributors and associates of the Imaginative Education Research Group.  Administrators have a web-based control panel to manage the people profiles in this database.

[http://ierg.net/people/ Visit the site]

| [http://solutions.weblite.ca Web Lite Solutions Corp.]

|-
| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://sustain-gradnetwork.envr.sfu.ca/]]
| '''Sustainability Research Database'''

A database at Simon Fraser University for grad students to post and share research profiles.

[http://sustain-gradnetwork.envr.sfu.ca/ Visit the site]

| [http://fas.sfu.ca Faculty of Applied Sciences Web Team]

|-
| [[Image:http://images.websnapr.com/?size=150&key=40f0knTakb1b&url=http://apps.weblite.ca/]]
| '''Web Lite Applications Catalog'''

A catalog of applications available through Web Lite Solutions.  Allows users to set up their own online applications on Web Lite's servers.  This site is completely powered by Xataface.

[http://apps.weblite.ca/ Visit the site]

| [http://solutions.weblite.ca Web Lite Solutions Corp.]
|}


","examples, samples",en,0
widget:editor,35,widget:editor,"==widget:editor fields.ini directive==

Return to [[fields.ini file]]

[[toc]]

The widget:editor directive is applicable in the [[fields.ini file]].  It specifies the type of HTML editor that should be used.  This directive is only used when [[widget:type]] is set to [[widget:type htmlarea|htmlarea]].  Xataface currently supports FCKEditor, TinyMCE, and NicEdit.

===Allowed Values===

{| class=""listing listing2""
|-
! Value
! Description
! Version
|-
| fckeditor
| Use [http://www.fckeditor.net/ FCKEditor].  This is the default value.
| all
|-
| tinymce 
| Use [http://tinymce.moxiecode.com/ TinyMCE editor].
| 0.6
|-
| nicedit
| Use [http://www.nicedit.com/ NicEdit].
| 1.0.5
|}

===Examples===

====Example 1: Using FCKEditor====

Given a field 'content' that you wish to be able to edit with FCKEditor, you would have the following section in your [[fields.ini file]]:

<code>
[content]
    widget:type=htmlarea
    widget:editor=fckeditor
</code>

Note that since FCKEditor is the default editor, the above would give the same result as:

<code>
[content]
    widget:type=htmlarea
</code>

====Example 2: Using TinyMCE====

Further from example 1, if we wanted to use TinyMCE editor, we would change our directive to:

<code>
[content]
    widget:type=htmlarea
    widget:editor=tinymce
</code>

====Example 3: Using NicEdit====

Further from example 1:

<code>
[content]
    widget:type=htmlarea
    widget:editor=nicedit
</code>

==Enabling Image Uploads==

By default image uploads are disabled in these WYSIWYG editors.

===Enabling Image Uploads in FCKEditor===

# Create a directory named ''uploads'' inside your application directory. e.g.<code>
cd /path/to/myapp/uploads
</code>
# Make the ''uploads'' directory writable by the webserver. e.g. <code>
chmod 777 /path/to/myapp/uploads
</code>
# Edit the ''lib/FCKeditor/editor/filemanager/connectors/php/config.php'' file inside your ''xataface'' directory so that:<code>
$Config['Enabled'] = true ;
$Config['UserFilesPath'] = '/url/to/myapp/uploads/' ;
    // The path portion of the URL to your uploads directory.
    // e.g. if your uploads directory is accessible at
    // http://example.com/myapp/uploads, then this value should
    // be /myapp/uploads/
$Config['UserFilesAbsolutePath'] = '/path/to/myapp/uploads/' ;
    // The absolute file system path to your uploads directory.
    // e.g. if your uploads directory is located at
    // /home/myhome/www/myapp/uploads, then this value should be
    // /home/myhome/www/myapp/uploads
</code>
# Now when you click on the ""Add Image"" link in your HTML editor, it will allow you to upload images and browse existing uploaded images.

",,en,0
about,36,about,"==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 ''xataface'' directory inside your application directory.
# Create a configuration file named ''conf.ini'' in your application directory with your database settings:<code>
[_database]
    host=localhost
    name=mydb
    user=me
    password=mypass

[_tables]
    ; A list of tables to include in your application's menu
    ; These tables must already exist in your database
    people=Profiles
    news=News Articles
</code>
# Create an .htaccess file in your application directory to prevent access to your ''conf.ini'' file:<code>
<FilesMatch ""\.ini$"">
Deny from all
</FilesMatch>
</code>
# Create a PHP script in your application directory as an access point for your app.  We'll call it ''index.php'':<code style=""php"">
<?php
// Include the Xataface API
require_once 'xataface/dataface-public-api.php';

// Initialize Xataface framework
df_init(__FILE__, 'xataface');
    // 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 =& Dataface_Application::getInstance();

// Display the application
$app->display()
</code>
# You'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 '''NOT''':

* 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'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====

* '''Out-of-the-box Database Front-end''' - With as little as 4 lines of PHP code, you can have a full-featured web application for your database.
* '''Simple, Intuitive User interface''' - Default application is consistent and simple to use.  There is a 'tables' menu, to select a table, and each table has ""details"", ""list"", and ""find"" tabs.  Very easy to navigate.
* '''Powerful configuration options''' - You can configure your application details (such as widget types) using simple configuration files.
* '''Extendible''' - You can modify your application as you see fit using configuration files and PHP delegate classes.
* '''Hooks''' - By observing simple conventions you can extend Xataface's functionality with hooks, triggers, and events.  E.g. add a function that is called after a record is inserted.
* '''Permissions''' - Powerful, pluggable permissions system.
* '''Authentication''' - Provides login/logout ability.  You just specify which table your users are stored in.
* '''Relationships''' - Tell Xataface how your tables are related to one another and it will provide you with more logical functionality for managing your data.
* '''Themeable''' - Xataface uses the Smarty template engine as a base, but extends it with some powerful new features such as extendable templates and theming support.
* '''Modular''' - 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====

* '''Automatic Form Generation''' - Automatically generates appropriate web forms to add new records and edit existing records.
* '''Widgets''' - Support for many different widget types including text fields, text areas, checkboxes, select lists, html editors, grids, file uploads, and more.
* '''Configurable''' - Customize forms using configuration files and delegate classes.
* '''Personalizable''' - Show different forms to different users depending on their permissions and preferences.
* '''Add Related Records''' - Insert records and automatically track their relationships to other tables.
* '''Editable Data Grid''' - Manage your data like a spreadsheet using the DataGrid module.
* '''Copy''' - Copy sets of records.
* '''Update Found Set''' - Update multiple records with one swipe.
* '''Fine-grained Permissions''' - Assign editing permission based on table, record, or field. 
* '''File uploads''' - Support for file uploads with storage either in a BLOB field or on the file system.
* '''Delete''' - Delete single record or delete the current found set.

====Searching====

* '''Automatic Find Form''' - The Xataface find form allows you to search a table on any field.
* '''Range Searches''' - Search for records matching values in a certain range (e.g. find all people between the ages of 20 and 30).
* '''Exact Matching''' - Search for exact matches.
* '''Partial Matching''' - Search for fields that contain a keyword phrase.
* '''Multi-field search''' - There is always a simple search field accessible which searches all fields in the current table.  E.g. a search for ""Tom"" would match any record in the current table that contained the phrase ""Tom"" in any of its columns.
* '''Related Record Searches''' - Find records that contain related records matching a search term.  (E.g. find all people who got an 'A' in a particular course).


====Browsing====

* '''Automatic Details View''' - Each record has user-friendly details page to browse the contents of the record.
* '''AJAX Record Tree''' - Provides optional AJAX record tree to browse the data in your database by relationships.
* '''Expand for More''' - Quickly expand a row in list view to see the full record details.
* '''Drag and Drop Reordering''' - The details view for a record can be broken up into related sections.  Users can reorder these sections via drag and drop.

====Exporting====

* '''RSS''' - Support for RSS 1.0, 2.0 and Atom feeds of any found set.
* '''XML''' - Export any found set as XML so that the data can be interchanged with other products (e.g. desktop publishing suites).
* '''CSV''' - Export any found set to CSV (comma-separated-value) to open in a spreadsheet application like Excel.
* '''JSON''' - 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====

* '''String Internationalization''' - 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.
* '''Dynamic Data Translation''' - Xataface even allows you to internationalize your existing database data without having to change your database structure.
* '''Templates''' - Includes a {translate} tag for Smarty templates to easily translate template text.
* '''In the background''' - 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.
* '''Translation Form''' - If multiple languages are enabled, Xataface provides a simple translation form to translate content between languages.
* '''Translation Status Tracking''' - Track the status of translations to mark whether they need to be retranslated.

====Importing====

* '''Import Filter API''' - Using delegate classes, it is easy to define an import filter to import any type of data into the database.
* '''User Preview''' - User can preview imported data before confirming that he wants to import it.

====History====

* '''Optional History Support''' - If history is enabled, all changes made to any data are recorded.
* '''Undo/Redo Support''' - Easily revert to an earlier version of a record.
* '''View Snapshot''' - Browse previous versions of records.
* '''View Diffs''' - View differences/changes between versions of records, similar to a wiki.

====Caching====

* '''Output cache''' - 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.
* '''APC Support''' - 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====

* '''Fine-grained permissions''' - 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.
* '''Cascading Permissions''' - 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.
* '''Role-based permissions''' - You can define """"""roles"""""" which are sets of permissions that can be assigned to users.
* '''Extendable Permissions Model''' - You can easily define your own permissions and roles, extending existing roles, custom for your application.
* '''Built-in Authentication''' - 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.
* '''Password Encryption''' - Xataface supports and is compatible with most of the standard password encryptions including MD5, SHA1, and MySQL Password.
* '''Pluggable Authentication''' - Easy to create your own authentication plugins in case you want to implement your own custom authentication.
* '''CAS''' - Module available for the Yale CAS (Central Authentication Service).
* '''LDAP''' - LDAP authentication module available.
* '''HTTP''' - Optional HTTP login support.  Standard login uses a web-based login form, but you can also use HTTP headers for authentication.

====Relationships====

* '''Powerful Relationship Model''' - It is easy to define relationships between your tables using simple configuration files.  Syntax is simple, but the results are powerful.
* '''Add New Related Record''' - Create a new record and add it to a parent record's relationship at the same time. (E.g. create a new ""course"" record and add it to a teacher's list of taught courses).
* '''Add Existing Related Record''' - Add an existing record to a parent record's relationship. (e.g. Add an existing course record to a teacher's list of taught courses).
* '''Remove related record''' - Remove a record from a relationship. (e.g. remove a course record from a teacher's list of taught courses).

====API====

Xataface includes a powerful API to allow you to more efficiently work with your database.

* '''Data Objects''' - Provides a simple API to work with database records.  Searching, loading, saving, editing, and deleting records supported.

====Templates====

* '''Smarty Template Engine''' - Xataface uses the Smarty template engine as a base, one of the fastest PHP template engines available.
* '''Template Inheritance''' - You can create templates that inherit from other templates, and replace the content in specified ""slots"" of the original template.  This drastically increases template reuse and development productivity.
* '''Cascading Support''' - 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'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 ""road blocks"", 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'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'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).",,en,0
URL_Conventions,37,URL_Conventions,"==Xataface URL Conventions==

[[toc]]

Xataface adheres to a few simple URL conventions for all of its actions.  When you understand how Xataface URLs work you begin to get far more out of your applications.  By specifying the appropriate query parameters to can jump directly to any point in your application, or produce a specific result set.

For example, the URL ''index.php?-table=people'' will take you to the ''people'' table (and since the default action for a Xataface application is ''list'', it will take you to the ''list'' view.

You could be more explicit by specifying the action in the URL directly: ''index.php?-table=people&-action=list''.  This would take you to the same screen.  From this example, you see that you can specify such things as the table and action via GET parameters.  Xataface accepts many more GET parameters also, as you'll see in the next section.

===Available GET Parameters===


{| class=""listing listing2""
|-
! Name
! Description
! Default
! Version
|-
| -action
| Specifies the action to perform.  E.g. ''browse'', ''list'', ''find'', ''edit'', ''new'', ... etc..
| list
| all
|-
| -table
| The name of the table to use as the context table.
| The first table in the [_tables] section of your [[conf.ini file]]
| all
|-
| -skip
| Skip a certain number of results in the current found set to display.  E.g. If there are 100 records in the table and you want to start browsing from the 30th record, you would set ''-skip=29''.

Not to be confused with the ''-cursor'' parameter which is used to specify which record to view in the ''details'' tab.
| 0
| all
|-
| -limit
| The maximum number of records in the found set to display.
| 30
| all
|-
| -cursor
| The index of the record in the current found set that is treated as the ""current"" record.  This is used in the ''details'' tab to identify which record to act on.  E.g. which record to view or edit.
| 0
| all
|-
| -sort
| A comma-delimited list of columns to sort the result set on.
| null
| all
|-
| -relationship
| If we are browsing related records, this specifies the name of the relationship.
| null
| all
|-
| -related:start
| If we are browsing related records, this is the first record in the relationship to show.
| 0
| all
|-
| -related:limit
| If we are browsing related records, this is the number of records to show per page.
| 30
| all
|-
| -search
| A keyword search term to filter the found set on.  Any row containing any field that matches the query will be returned.
| null
| all
|-
| --no-query=1
| A flag to indicate that xataface should not query the database by default.  This flag is used in the new record form to prevent the form parameters from being interpreted as query parameters to search in the database.  If you set this flag, it likely result in a message saying ""No records found"".  Generally you would only use this in a custom action where you are not relying on Xataface's default found set.
| 0
| 1.3
|}

There are many other GET parameters that are used in various contexts but the above parameters are available throughout the entire application.

===Finding Records using the URL===

Notice that all of the GET parameters mentioned in the previous section begin with a hyphen (i.e. '-').  This is a convention Xataface uses to distinguish directives from search queries.  All parameters that do not begin with '-' are treated as a query to filter the found set.

For example, ''first_name=bob'' used as a GET parameter would cause the found set to be filtered so that only records where the ''first_name'' column contains the phrase ""bob"" are returned.  Putting this all together, suppose we wanted to show the list tab for the ''people'' table, but only wanted to show the people with first names containing ""bob"":

index.php?-action=list&-table=people&first_name=bob

====Exact, Range, and Pattern Matching====

By default, queries on text columns look for partial matches.  I.e. if you search for ""bob"" it will match ""bob"", ""bobby"", ""rubob"", and any other text that contains ""bob"".  If you are only interested in finding records that match ''exactly'' ""bob"", then you can prepend an ""="" to the query.  E.g. ''first_name==bob'', or the full URL:

index.php?-action=list&-table=people&first_name==bob

This should show the ''list'' tab for the ''people'' table with only records with first name exactly ""bob"".

There are a number of modifiers that you can prepend to your query to modify how it is executed.  They are as follows:

=====Search Operators=====

{| class=""listing listing2""
|-
! Prefix
! Usage Example
! Description
|- 
| >
| age=>10
| Match records greater than search parameter.
|-
| <
| age=<10
| Match records less than search parameter.
|-
| >=
| age=>=10
| Match records greater than or equal to the search parameter.
|-
| <=
| age=<=10
| Match records less than or equal to the search parameter.
|-
| ..
| age=10..20
| Match records in a given range.
|-
| =
| first_name==bob
| Match records that exactly match the search parameter (if there is no prefix then it will search for partial matches on text/varchar/char fields.).
|-
| ~
| first_name=~a%
| Exact match, but you can include wildcards such as '%' and '?' in your search.
|}


=====Search Examples=====

Given the following data set:

{| class=""listing listing2""
|-
! first_name
! age
|-
| Bob
| 10
|-
| Cindy
| 12
|-
| Julie
| 6
|-
| Jake
| 8
|-
| Kabob
| 16
|}

Here are some example queries on this data set and their results:

{| class=""listing listing2""
|-
! Query
! Matches
|- 
| age=>10 
| match records where ''age'' is greater than 10.  This includes ''Cindy'' and ''Kabob''.
|-
| age=<10 
| match records where ''age'' is less than 10.  This includes ''Julie'' and ''Jake''
|-
| age=>=10 
| match records where ''age'' is greater or equal to 10.  This includes ''Bob'', ''Cindy'', and ''Kabob''.
|-
| age=<=10
| match records where ''age'' is less than or equal to 10. This includes ''Bob'', ''Julie'', and ''Jake''.
|-
| age=8..10
| match records where ''age'' is between 8 and 10.  This includes ''Bob'' and ''Jake''.
|-
| first_name=bob
| Matches records where ''first_name'' contains ""bob"".  This includes ''Bob'' and ''Kabob''.
|-
| first_name==bob
| Matches records where ''first_name'' is exactly ""bob"".  This includes ''Bob'' only.
|-
| first_name=~J%
| Matches records that begin with ""J"".  This includes ''Jake'' and ''Julie''
|}

====Matching on Related Records====

It is also possible to match records based on their related data (i.e. data that is not physically stored in the record itself, but in related records via a relationship).  For example if we want to find authors who have written about a particular topic, we would normally have to first find all of the articles that contain a topic, and then cross-reference that result against the ''authors'' table.  With Xataface we can perform this query directly from the ''authors'' table using something like the following query:
 index.php?-table=authors&articles/title=sports
This assumes that the ''authors'' table has a relationship named ''articles'' that contains all of the articles that an author has written.  So the above query returns precisely those authors who have written at least one article whose ''title'' field contains the phrase ""sports"".


=====Anatomy of a Related Query=====

 %relationship%/%field%=%query%
This matches all records in the current table such that at least one record in its ''<relationship>'' relationship matches the query: ''%field%=%query%''.


====Using the ''OR'' Operator====

Xataface allows you to search for more than one value at a time using the ''OR'' operator.  E.g.
 first_name=bob+OR+steve
Would match all records with ''first_name'' containing ""bob"" or ""steve"".
 first_name=bob+OR+=steve
Would match all records with ''first_name'' containing ""bob"" or exactly matching ""steve""
 age=<10+OR+>20
Would match all records with age less than 10 or greater than 20.

====Combining Multiple Queries in One Request====

Xataface allows you to filter on more than one field at a time.  If you combine multiple queries in the same request it has the effect of strengthening the filter, matching only those rows that match ''both'' queries.  E.g.
 age=>10&first_name=bob
would match all records where ''age'' is greater than 10 '''AND''' that have ''first_name'' containing ""bob"".

=====Examples of Combined Queries=====

Given the same data set as the previous set of examples:

{| class=""listing listing2""
|-
! first_name
! age
|-
| Bob
| 10
|-
| Cindy
| 12
|-
| Julie
| 6
|-
| Jake
| 8
|-
| Kabob
| 16
|}

 first_name=bob&age=11
would return no matches because there are no records that contain both ''first_name'' ""bob"" and ''age'' 11.  However
 first_name=bob&age=10
would return only ''Bob'' and
 first_name=bob&age=16
would return only ''Kabob''.

====Special Common Queries====

=====Search For Null or Blank Value=====

Searching for a null value or a blank value is an exact match for """".  Therefore you can simply search for ""="".  E.g. To find records with a null or blank first_name you would use the query ''first_name==''.  Or the full query:
 index.php?-table=people&first_name==

=====Search for Non-blank Value=====

Searching for a non-blank value is the same as searching for a value greater than """".  Therefore you can simply search for "">"".  E.g. if you wanted to find records with a first_name, you would use the query ''first_name=>''.  Or the full query:
 index.php?-table=people&first_name=>

==Preserved vs Non-preserved Parameters==

As mentioned above any parameters that are prefixed by a hyphen (i.e. ""="") are treated as directives rather than search filters.  Hence if you want to use your own GET parameters you should always prefix them with a ""-"" to ensure that Xataface does not attempt to apply it as a search filter.  In order to keep a consistent context for users, all browsing within the same table preserves both search queries and directives.  Hence if you go to the URL:
 index.php?-table=people&-action=list&first_name=bob
It will show you the ''list'' tab of the ''people'' table with only those records with ''first_name'' ""bob"".  Now if you click on the ''details'' tab it will preserve your query ''first_name''.  The query will become something like:
 index.php?-table=people&-action=details&first_name=bob&...etc... more parameters
(Although the parameters may appear in a different order).  This allows you to navigate forward and back to previous and next records and stay within the same found set.  It also ensures that if you click on the ''list'' tab to return to the list view, it will retain your place in the list.

Note that navigating within the same table it will also preserve your directives.  E.g. If you specify the ''-limit'' directive to show 100 records per page:
 index.php?-table=people&-action=list&-limit=100
And then you click on the ''details'' tab, it will retain your ''-limit'' parameter.  Of course the ''-limit'' parameter is not actually used by the ''details'' action because it works on only one record at a time (it uses the ''-cursor'' parameter instead), when you click back on the ''list'' tab it will still show you 100 records per page.

Because of this, we call the ''-limit'' parameter a preserved parameter.  It is retained when navigating within the same table.  '''Note:''' parameters are retained in the HTTP Query string, not in sessions or cookies.  This ensures that there are no surprises when you enter a URL to your Xataface application.

===Unpreserved Parameters===

If you ''don't'' want Xataface to preserve one of your parameters, you should prefix two hyphens to the parameter name.  I.e. ""--"".  One example of an unpreserved parameters throughout Xataface applications is the ''--msg'' parameter.  The value of this parameter will be displayed on the page as an info message to the user.  Clearly you don't want this parameter preserved across requests, as you only want the user to see a message once.  E.g.
 index.php?--msg=Record+Successfully+saved.
Would didsplay the mesage ""Record Successfully Saved"" at the top of the page.  If you click on any link in the application, it will not retain the ''--msg'' parameter so you will not see the message on subsequent requests.

This parameter is useful if you want to give feedback to the user about an action that has been carried out.

===Summary===

{| class=""listing listing2""
|-
! Parameter Type
! Prefix
! Examples
! Description
|-
| Preserved
| -
| -limit, -skip, -cursor, -action, -table
| Parameter value is preserved when user navigates away from the page (within the same table).
|-
| Unpreserved Parameters
| --
| --msg
| Parameter is ''NOT'' retrained with the user navigates away from the page.
|}





","URL Conventions, GET Parameters, POST parameters, Request Parameters",en,0
How_to_build_a_PHP_MySQL_Application_with_4_lines_of_code,38,"How to build a PHP MySQL Application with 4 lines of code","'''The [http://xataface.com Xataface Application Framework] allows you to convert your existing MySQL database into a full-fledged with as little as 4 lines of code.  And it's Not a code generator.'''

[[toc]]

This article is intended to spark interest in the [http://xataface.com Xataface Application Framework] amongst PHP developers by showing how easy it is to set up a full-featured front-end for your MySQL database.  If you are a PHP developer, surly you can identify with the situation where you've built a snazzy website with PHP and MySQL but you need to create some way the website users to administer it.  I.e., you need to make an administrative back-end for your users.

You need to do this because PHP admin is too technical for your users, and it is an aweful lot of tedious work to create all of the necessary forms and lists for your users to edit the data themselves.

===Features for our Application===

* Create, edit and delete records using simple web forms.
* Browse through database and find records without any SQL.
* Lots of great widgets for editing records including html editors, select lists, grids, checkboxes, calendars and more.
* Sort records.
* Export result sets as CSV or XML.
* Fully configurable and extendable by you to implement more [[about|features]].

===Creating the Application===

Here are 6 steps to a full-featured front-end for your database:

# Create a directory for your application on your webserver.  Call it ''myapp''.
# Download the latest version of [http://xataface.com Xataface] and copy it into your application directory that we just created.  (i.e. ''myapp/xataface''.
# Create a configuration file named ''conf.ini'' inside your application directory (i.e. ''myapp/conf.ini'') to store your database connection info:<code>
[_database]
    host=localhost
    name=mydb
    user=username
    password=mypass

[_tables]
    ;; This section lists the tables to include in your application menu
    table1=Label for table 1
    table2=Label for table 2
</code>
# Create an .htaccess (i.e. ''myapp/.htaccess'') file to prevent Apache from serving your ''conf.ini'' file:<code>
<FilesMatch ""\.ini$"">
Deny from all
</FilesMatch>
</code>  '''Note:  If you are not using Apache as your web server you'll need to block access to the .ini files using a different mechanism.  E.g. On IIS you can create a Web.config file to block this access and place it inside your application's directory.'''  Download a sample Web.config file [http://weblite.ca/svn/dataface/core/trunk/site_skeleton/Web.config here].
# Create an index.php file (i.e. ''myapp/index.php'') to serve as an access point for your application:<code>
<?php
// Include the Xataface API
require_once 'xataface/dataface-public-api.php';

// Initialize Xataface framework
df_init(__FILE__, 'xataface')->display();
    // 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)
</code>
# Create a ''templates_c'' directory to store cached smarty templates or your application (i.e. ''myapp/templates_c'', and make sure that it is writable by the webserver:
 $ mkdir templates_c
 $ chmod 777 templates_c


That's all there is to it!  Point your web browser to the index.php file we just made, and check out your new app!

===Screenshots of Our App===

====Find Form====

[[Image:http://media.weblite.ca/files/photos/people-find.png?max_width=400]]

====New Record Form====

[[Image:http://media.weblite.ca/files/photos/people-new-record.png?max_width=400]]

====List View====

[[Image:http://media.weblite.ca/files/photos/people-list.png?max_width=400]]

===Where to go now===

# Sign up for the Xataface mailing list to receive exclusive development tips (see the left column for a signup form).
# Check out the [[about|About Xataface]] page for more information about features and requirements.
# Use the [http://xataface.com/documentation/getting_started Getting Started Tutorial] to get started making your own application.
# [http://xataface.com/videos Watch screencasts] showing Xataface in action.



","tutorial, getting started, installation, first app, 4 lines of code",en,0
Drag_and_Drop_Reordering_of_Relationships,39,Drag_and_Drop_Reordering_of_Relationships,"==Drag and Drop Reordering of Related Records in Xataface==

One powerful aspect of Xataface is its abstraction of relationships between tables.  Once you define a relationship users can browse related records, add new and existing related records, and delete related records to or from the relationship.  For example, suppose you have a ''people'' table and a ''publications'', you could define a relationship from ''people'' to ''publications'' to identify publications that belong to a particular person.  The table's might look something like:

===people table===

{| class=""listing listing2""
! person_id
! person_name
|-
| 1
| John Smith
|-
| 2
| Ben Stein
|-
| 3
| Harley Davidson
|-
| 4
| Trevor Linden
|}


===publications table===

{| class=""listing listing2""
! publication_id
! owner_id
! pub_title
|-
| 1
| 2
| Introduction to widgetry
|-
| 2
| 2
| Intermediate Widgetry
|-
| 3
| 2
| Advanced Widgetry
|-
| 4
| 3
| How to play the violin
|}


See http://xataface.com/documentation/tutorial/getting_started/relationships for an introduction to relationships in Xataface, and how to define them.

Our relationship definition in the  ''people'' table's [[relationships.ini file]] might look something like:

<code>
[my_pubications]
    publications.owner_id=""$person_id""
</code>

This indicates that any publication whose ''owner_id'' column matches the current ''people'' record's ''person_id'' field is considered part of the relationship.  Using our example data above, this would mean that Ben Stein's ''my_publications'' relationship would contain 3 records: ""Introduction to Widgetry"", ""Intermediate Widgetry"", and ""Advanced Widgetry"".  In our Xataface application this means that in the ""Details"" tab for the ""Ben Stein"" record, we would see a sub-tab ''My Publications'' which would contain a list of Ben Stein's publications.

===Adding Publication Order===

Now that we have our relationship, what if Ben Stein wants his publications to appear in a particular order whenever they are displayed to the user.  Xataface allows us to specify an ""order"" column for our relationship, which will cause the related records to be orderable by drag and drop (if the user has appropriate permissions).

# Add a field to the ''publications'' table named ""pub_order""
# Change the relationship definition in the people table's [[relationships.ini file]] to tell Xataface to use the pub_order field for sorting:<code>
[my_pubications]
    publications.owner_id=""$person_id""
    metafields:order=""pub_order""
</code>

Now load up your application and navigate to the ""My Publications"" tab for the ""Ben Stein"" record. Now you're able to drag and drop rows in your application to reorder them.

===Permission to Reorder Records===

Only users who have been assigned the ''reorder_related_records'' permission for a record's relationship are allowed to reorder records of that relationship.  By default the ''EDIT'' role contains this permission, as does any role that permits the user to edit the parent record of the relationship.  The ''READ ONLY'' role does not contain this permission.  If you want to explicitly deny this permission for all relationships in a record, you can simply set this permission to 0 in the associated role within your application's [[permissions.ini file]]:

<code>
[MY ROLE]
     reorder_related_records=0
</code>

For more information about permssions see:

* [[permissions.ini file|The Permissions.ini file reference]]
* [http://xataface.com/documentation/tutorial/getting_started/permissions Introduction to Permissions]

===Loading Related Records using the Xataface API===

The ordering that is set via this drag and drop method is also honoured by the Xataface API when fetching related records.  You can load related records using the [http://dataface.weblite.ca/getRelatedRecordObjects getRelatedRecordObjects] method of the [http://dataface.weblite.ca/Dataface_Record Dataface_Record] class. E.g.

<code>
$benStein = df_get_record('people', array('person_id'=>2));
$pubs = $benStein->getRelatedRecordObjects('my_publications');
foreach ($pubs as $pub){
    echo $pub->val('pub_title').'<br/>';
}
</code>
This will list up to the first 30 publications of Ben stein in the order prescribed by our drag and drop ordering scheme.
",,en,0
Introduction_to_RSS_Feeds_in_Xataface,40,Introduction_to_RSS_Feeds_in_Xataface,"==Introduction to RSS Feeds in Xataface==

[[toc]]

A default Xataface application provides RSS feeds to any found set in your application.  This article explains a little bit about RSS and how you can configure Xataface to give you the desired results for your RSS feed.

===What is RSS?===

From [http://en.wikipedia.org/wiki/RSS_(file_format) Wikipedia's RSS article]:

""RSS is a family of Web feed formats used to publish frequently updated works such as blog entries, news headlines, audio, and videoin a standardized format.[2] An RSS document (which is called a ""feed"", ""web feed"",[3] or ""channel"") includes full or summarized text, plus metadata such as publishing dates and authorship. Web feeds benefit publishers by letting them syndicate content automatically. They benefit readers who want to subscribe to timely updates from favored websites or to aggregate feeds from many sites into one place. RSS feeds can be read using software called an ""RSS reader"", ""feed reader"", or ""aggregator"", which can be web-based or desktop-based. A standardized XML file format allows the information to be published once and viewed by many different programs. The user subscribes to a feed by entering the feed's URI (often referred to informally as a ""URL"", although technically, those two terms are not exactly synonymous) into the reader or by clicking an RSS icon in a browser that initiates the subscription process. The RSS reader checks the user's subscribed feeds regularly for new work, downloads any updates that it finds, and provides a user interface to monitor and read the feeds.""

In a way RSS replaces email subscriptions so that you can subscribe to receive updates when content is added or changed on websites that you monitory.  This way you can monitory these changes in your RSS reader so that your email box doesn't get clogged up.

===Using RSS in Xataface===

Xataface allows you to subscribe to:

# Entire tables
# Any found set
# Changes to a particular record
# Related record lists

====Example 1: Subscribing to receive news updates====

A user wants to be alerted whenever a new item is inserted into the ''news'' table, so he navigates to the ''list'' tab of the ''news'' table, and clicks the RSS Feed icon in the upper right.  If he has an RSS reader application set up, this is all he has to do to subscribe to the RSS feed for the ''news'' table.  When new records are inserted, he'll receive alerts in his RSS reader.

====Example 2: Subscribing to receive found set updates====

A user wants to be alerted whenever a new item is inserted into the ''news'' table that contains the phrase ""Buffalo Bills"", because he is a Buffalo Bills fan.  So he navigates to the ''news'' table, and does a search for the phrase ""Buffalo Bills"".  Then he clicks on the ""RSS Feed"" icon in the upper right of the result set list.  If he has an RSS reader application set up, this is all he has to do to subscribe to the RSS feed for ''news'' items containing the phrase ""Buffalo Bills"".  Whenever a new item is posted with this phrase, he will be notified via RSS of the new record.

====Example 3: Subscribing to a related list====

Suppose you want to receive updates whenever a particular author adds a book to his list of published works.  Further suppose this is represented by a relationship between the ''authors'' table and the ''books'' table named ''publications''.  You can subscribe to the RSS feed for his publications by navigating to the ''publications'' tab for that author, then clicking on the ""RSS Feed"" icon in the upper right.  Now whenever this author adds a new book to his publications list, you'll be notified via RSS.



===Example usage in Xataface===

# A user wants to be alerted whenever a new item is inserted into the ''news'' table, so he navigates to the ''list'' tab of the ''news'' table, and clicks the RSS Feed icon in the upper right.  If he has an RSS reader application set up, this is all he has to do to subscribe to the RSS feed for the ''news'' table.  When new records are inserted, he'll receive alerts in his RSS reader.
# A user wants to be alerted whenever a new record about ""Wayne Gretzky"" is inserted in to the ''news'' table.  He navigates to the ''news'' table, then performs a search for ""Wayne Gretzky"" using the top right search box.  Then, he clicks on the ""RSS Feed"" icon in the upper right of the result list.  Now, whenever a new item is inserted with the phrase ""Wayne Gretzky"", the user will be notified via RSS.

===Configuring RSS Feeds===

As with everything else in Xataface, you can configure your RSS feeds to appear just as you want them to.  The following delegate class methods are available to be defined in the table delegate class for your feed:

{| class=""listing listing2""
! 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
|-
| getRSSDescription
| Overrides the default generated RSS description for a record.
| 1.0
|-
| [[getSingleRecordSearchFeed]]
| Overrides the default feed for a subsearch within a record.  This works identically to the [[getFeed]] method except that it takes 2 parameters: one for the current record, and a second parameter for the query.
| 1.2.3
|}

==Example Configuration==

There are 2 parts to configuring your RSS feeds.

# Configuring the feed as a whole
# Configuring the feed items (that is each record that will appear in your RSS feed).

===Configuring the Feed as a whole===

For configuring the feed as a whole, we have 2 options.  We can specify the title, description, and link for the feed in the ''[_feed]'' section of your [[conf.ini file]].  This is sort of a ""one size fits all"" approach where all feeds generated from your application will share the same title.

E.g.

<code>
[_feed]
    title=""My Site News""
    description=""News updates from my site""
    link=""http://www.example.com""
</code>

However, if we want our feed's information to depend on the user's query (e.g. what the user was searching for, or which table the feed is generated on, we have more flexibility if we define the [[getFeed]] method in either the [[Application Delegate Class|application delegate class]] or the [[Delegate class methods|table delegate class]].  E.g.

<code>
function getFeed($query=array()){
    $params = array();
    if ( @$query['-search'] ) $params['title'] = '""'.$query['-search'].'"" results';
    else $params['title'] = 'All records from my table';
    return $params;
}
</code>

Notice that I don't need to define all possible parameters.  Any parameters that I don't define will be provided automatically by Xataface, or it will simply use the values specified in your ''[_feed]'' section of the [[conf.ini file]].

===Configuring Feed Items===

Configuring the feed items is quite important for ensuring that subscribers are seeing what you want them to see in the RSS feed.  Xataface tries to guess appropriate content for your feed items if you don't specify it explicitly, but you'll likely want to tweak it a little bit to make the feed look more polished for your purposes.

Use the [[getFeedItem]] [[Delegate class methods|delegate class method]] to specify how a feed item behaves (e.g. the title, content, date, author, link).

E.g.

<code>
function getFeedItem(&$record)){
    return array(
        'description' => $record->val('body')
    );
}
</code>

Once again, notice that we don't need to specify all available options.  Only those options that we want to override.  In this case we want the description of the feed item to simply display the body of our news item.  The description of an RSS feed item is effectively the body text that the user sees why they click on an item in their news reader, so this is quite important.


","RSS Feeds",en,0
getFeedItem,41,getFeedItem,"==getFeedItem() Delegate Class Method==

[[toc]]

===Synopsis:===

The getFeedItem() method of a table [[Delegate class methods|delegate class]] returns an associative array of parameters for a record as it should appear as part of an [[Introduction_to_RSS_Feeds_in_Xataface|RSS feed]].  An RSS feed item consists of the following components:

# '''title''' - The title of the record as it appears in the RSS feed.
# '''description''' - The description of the record for the RSS feed.  This is really the body of the RSS feed item.
# '''link''' - The linkback URL if users want to know more about the record.
# '''date''' - The date that the record was posted/modified.
# '''author''' - The name of the person who posted this record.
# '''source''' - URL to the site where record originated from.

===Parameters===

# '''Dataface_Record''' &$record - The record that is being represented in an RSS feed.

===Return Value===

The getFeedItem() method returns an associative array with the components of the RSS feed.  This array does not need to contain all possible keys, or even any keys.  Any keys that are omitted will simply use default values in the RSS feed.  The array may contain the following keys:

{| class=""listing listing2""
! Name
! Description
! Version
|-
| title
| The record title as it appears in RSS feeds.  If this is omitted, the RSS feed will simply use the output of [http://dataface.weblite.ca/Dataface_Record Dataface_Record's] [http://dataface.weblite.ca/getTitle getTitle()] method.
| 1.0
|-
| description
| The record description.  This is used in the main body of the RSS feed.   If this is omitted, the RSS feed will use an HTML table that shows all of the field data in the record.  This value can also be overridden using the [[getRSSDescription]] method of the delegate class.
| 1.0
|-
| link
| The URL to this record.  If this is omitted it just points to the ''view'' tab for this record.  However you can direct it anywhere you like.  When the user clicks on the ""More Info"" link in his RSS reader it will direct him to this link.
| 1.0
|-
| date
| The date that this record was posted or last modified.  This is the date that an RSS reader will use to decide if it has already loaded the record yet.  If this is omitted it will try the [http://dataface.weblite.ca/Dataface_Record Dataface_Record's] [http://dataface.weblite.ca/getLastModified getLastModified()] method to obtain the last modified date of the record.  Failing that, it will use [http://dataface.weblite.ca/Dataface_Record Dataface_Record's] [http://dataface.weblite.ca/getCreated getCreated()] method to try to obtain the creation date of the record.  This date should be a unix timestamp.
| 1.0
|-
| author
| The name of the user who posted this record.  If this is omitted, then it will try to use [http://dataface.weblite.ca/Dataface_Record Dataface_Record's] [http://dataface.weblite.ca/getCreator getCreator()] method.  Failing that, it will use the value of the ''default_author'' parameter in the ''[_feed]'' section of the [[conf.ini file]].  If that is not defined, then it simply uses the string ""Site Administrator"".
| 1.0
|-
| source
| The source URL where the feed is to have originated.  If none is specified, then it will use the value of the ''source'' parameter in the ''[_feed]'' section of the [[conf.ini file]].  Failing that, it will simply use the URL to the application.

Note that you can alternatively define this value using the [[getFeedSource]] method.
| 1.0
|}

===Example===

<code>
function getFeedItem(&$record){
    return array(
        'title' => ""News Item: "".$record->getTitle(),
        'description' => $record->display('News Body'),
        'link' => $record->getPublicLink(),
        'date' => strtotime($record->val('last_modified')),
        'author' => $record->val('posted_by'),
        'source' => 'http://www.example.com'
    );
}

</code>

'''Note that RSS feeds will work perfectly well without defining this method.  This just allows you to customize one or more parameters of the RSS feed'''.

===See Also:===

* '''[[getFeed]]''' - A delegate class method available to both the [[Application Delegate Class]] and the [[Delegate class methods|table delegate classes]] to configure the RSS feed as a whole (not just for an individual item in the RSS feed.
* '''[[getRelatedFeed]]''' - A [[Delegate class methods|delegate class method]] available to both the [[Application Delegate Class|application delegate class]] and the [[Delegate class methods|table delegate classes]] to configure the [[Introduction to RSS Feeds in Xataface|RSS feed]] for a related records list.
* '''[[getRSSDescription]]''' - A delegate class method to override the description that appears for a particular record in an RSS feed.  (The same as the ''description'' parameter of the [[getFeedItem]] method.
* '''[[Introduction to RSS Feeds in Xataface]]''' - An overview of Xataface's RSS feed support.",,en,0
getFeed,42,getFeed,"==getFeed() Delegate Class Method==

[[toc]]

===Synopsis:===

The getFeed() method of a table [[Delegate class methods|delegate class]] or [[Application Delegate Class|application delegate class]] returns an associative array of parameters to configure the [[Introduction_to_RSS_Feeds_in_Xataface|RSS feed]] for a particular table .  An RSS feed consists of the following components:

# '''title''' - The title of the RSS feed as it should appear in the subscribers' feed list.
# '''description''' - Describes the RSS feed.
# '''link''' - A link to the RSS feed
# '''syndicationURL''' - The URL to this RSS feed's site.

===Parameters===

# '''array''' $query - The HTTP query.  Contains information like the current table, current action, and search parameters.  This allows you to customize your RSS feed depending on the user's query parameters.

===Return Value===

The getFeed() method returns an associative array with the components of the RSS feed.  This array does not need to contain all possible keys, or even any keys.  Any keys that are omitted will simply use default values in the RSS feed.  The array may contain the following keys:

{| class=""listing listing2""
! Name
! Description
! Version
|-
| title
| The title for the RSS feed.  If this omitted, it will try to use the ''title'' directive of the ''[_feed]'' section of the [[conf.ini file]].  Failing that, it will try to generate an appropriate title for the feed depending on the current query.
| 1.0
|-
| description
| A Description for this RSS feed.  If this is omitted, it will try to use the ''description'' directive of the ''[_feed]'' section of the [[conf.ini file]].
| 1.0
|-
| link
| A link to the source page of the RSS feed.  If this is omitted, it will try to use the ''link'' directive of the ''[_feed]'' section of the [[conf.ini file]].
| 1.0
|-
| syndicationURL
| A link to the source page of the RSS feed.  If this is omitted, it will try to use the ''syndicationURL'' directive of the ''[_feed]'' section of the [[conf.ini file]].
| 1.0
|}

===Example===

<code>
function getFeed(&$query){
    return array(
        'title' => ""RSS feed for the "".$query['-table']."" table."",
        'description' => ""News and updates for automobiles"",
        'link' => df_absolute_url(DATAFACE_SITE_HREF),
        'syndicationURL' => df_absolute_url(DATAFACE_SITE_HREF)
    );
}

</code>

'''Note that RSS feeds will work perfectly well without defining this method.  This just allows you to customize one or more parameters of the RSS feed'''.

===See Also:===

* '''[[getFeedItem]]''' - A delegate class method available to both the [[Delegate class methods|table delegate classes]] to configure parameters for the particular items of the RSS feed.
* '''[[getRelatedFeed]]''' - A [[Delegate class methods|delegate class method]] available to both the [[Application Delegate Class|application delegate class]] and the [[Delegate class methods|table delegate classes]] to configure the [[Introduction to RSS Feeds in Xataface|RSS feed]] for a related records list.
* '''[[getRSSDescription]]''' - A delegate class method to override the description that appears for a particular record in an RSS feed.  (The same as the ''description'' parameter of the [[getFeedItem]] method.
* '''[[Introduction to RSS Feeds in Xataface]]''' - An overview of Xataface's RSS feed support.",,en,0
Calendar_Action,43,Calendar_Action,"==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:

<nowiki>
<div style=""text-align:center;border: 1px solid #ccc; padding: 10px"">
<img src=""http://media.weblite.ca/files/photos/Picture -4.png?max_width=500""
onmouseover=""this.src='http://media.weblite.ca/files/photos/Picture -4.png';""
onmouseout=""this.src='http://media.weblite.ca/files/photos/Picture -4.png?max_width=500';""/>
</div>
</nowiki>

===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 ''Lessons'' that stores information about scheduled music lessons.  If I want to add the calendar to this table, then I would add an ''[[actions.ini file]]'' to the ''tables/Lessons'' directory with the following contents:<code>
[calendar > calendar]
    condition=""true""
</code>
This overrides the calendar action which is disabled by default, and enables it for the ''Lessons'' 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 ''Lessons'' table I have the following fields that are relevant here:

* ''lesson_date'' - A date field containing the date and start time of the event.
* ''start_time'' - 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 ''Lessons'' table:

* ''event.date=1'' - Specifies that the field stores the date of the event.
* ''event.start=1'' - Specifies that the field stores the start time of the event.

So in our case we'll modify the [[fields.ini file]] as follows:

<code>
[lesson_date]
    event.date=1

[start_time]
    event.start=1
</code>

Now if we load up our application, we should now see a ''calendar'' tab along side ''list'', ''details'', and ''find'' for the ''Lessons'' 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 ''event.date'' and ''event.start'' directives for the same field.  For example if the ''lesson_date'' was a datetime field that marked the date and time of the lesson, we would modify our [[fields.ini]] file as follows:

<code>
[lesson_date]
    event.date=1
    event.start=1
</code>

===Available Fields===

The Calendar action will look for the following pieces of information in your records:

{| class=""listing listing2""
! 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
|}",,en,0
timestamp,44,timestamp,"Return to [[fields.ini file]]

A very simple sample of this could be your table contains the table date_created as a type of date.  In your fields.ini, you would include this:

<code>
[date_created]
timestamp=insert
widget:type=hidden
</code>

The widget:type=hidden will make the field not visible during entry and editing.  And the timestamp=insert causes the field to be filled upon insertion of a new record.

===Possible Values===

* '''update''' - Causes timestamp to be updated whenever the record is modified.
* '''insert''' - Causes the timestamp to be updated only when the record is first inserted.","timestamp, date, datetime",en,0
_output_cache,45,"The Xataface Output Cache","<nowiki><div class=""portalMessage"">Note: There was a bug in the output cache affecting Xataface version 1.0 to 1.3rc1.  If you are using a version of Xataface older than 1.3rc2 then you should either disable the output cache, or replace the Dataface/OutputCache.php file with one from a newer version.</div></nowiki>

[[toc]]

Xataface does quite a bit of heavy lifting on each page request.  If your application is getting a lot of traffic that is slowing your server down, you may want to look at enabling the Xataface output cache.

===Features===

* Improve speed of application dramatically - especially for seldom updated sites.
* Supports multiple languages.
* Supports multiple users (each user has own cache).
* Provides GZIP compression for improved performance.

===How it works?===

When you receive a request, Xataface will return a cached version of the page if the page has been accessed before.  If the page doesn't yet exist in the cache it generates the page, saves it to the cache and outputs it to the user transparently.  The cache is completely transparent to your users.

===Where is the cache stored?===

Xataface creates a table called ''__output_cache'' that stores all of the cached content for your application.  This table stores both a GZIPed and regular version of each page.  If the user's browser supports GZIP compression, Xataface will automatically return the GZIP version.  This results in further performance improvements.

===What if I make changes to the database?===

Xataface records which tables were in use when a page is cached.  If any of those tables are modified after the page is cached, Xataface will mark that cached page as ''out of date'' and regenerate it the next time that it is requested.

===What if I make changes to my configuration files and templates?===

The output cache will have to be manually cleared if you make any changes to your source files (e.g. PHP, templates, and INI files).  Clearing the cache is as easy as deleting or emptying the ''__output_cache'' table.

===How do I enable the Cache?===

Add the following to your [[conf.ini file]]:

<code>
[_output_cache]
    enabled=1
</code>

===How do I disable the Cache?===

Simply comment out or remove the ''[_output_cache]'' section of your [[conf.ini file]].  E.g.
<code>
;[_output_cache]
;   enabled=1
</code>

===Configuration Options===

The following directives can be added to the ''[_output_cache]'' section of your [[conf.ini file]] to customize how your output cache works.

{| class=""listing listing2""
|-
! Name
! Description
! Version
|-
| lifeTime
| Number of seconds before cached page is considered ''out of date''.
| 0.7
|-
| tableName
| The name of the table to store the cached pages.  Default '__output_cache'.
| 0.7
|-
| ignoredTables
| A comma-delimited list of tables that don't affect the output cache (i.e. these tables can be changed without causing the output cache to be refreshed.
| 0.7
|-
| observedTables
| A comma-delimited list of tables that should affect the status of the output cache for every page (whether the table is explicitly used by the page or not).  This is a useful way to tell Xataface to refresh your cache.
| 0.7
|-
| exemptActions
| A comma-delimited list of actions that are exempt from the output cache (and thus should not be cached).
| 0.7
|}","output cache",en,0
widget:atts,46,widget:atts,"==widget:atts Directive Reference==

The widget:atts directive in the fields.ini file allows any arbitrary HTML attributes to be added to any of the fields.  It may also be used to specify javascript event handler functions that the widget should call upon the specified event.  In particular, here are some examples of possible widget:atts directives:

===Available Widget Event Handlers===

{| class=""listing listing2""
|-
! name
! description
! version
|-
| [[field_size|widget:atts:size]]
| This directive sets the length of the input area a text box field, but it does not limit the number of characters that can be entered.  For example: <nowiki><br/>widget:atts:size = 50</nowiki>
| ?
|-
| [[field_maxlength|widget:atts:maxlength]]
| This directive limits the maximum number of characters that can be entered into a text box field.  For example: <nowiki><br/>widget:atts:maxlength = 25</nowiki>
| ?
|-
| [[field_style|widget:atts:style]]
| This directive specifies the style (font-size, font-family, etc.) for the field.  For example: <nowiki><br/>widget:atts:style = ""font-size: 24pt; font-family: Apple Chancery""</nowiki>
| ?
|-
| [[field_rows|widget:atts:rows]]
| This directive specifies the number of rows for a text area field to display.  For example: <nowiki><br/>widget:atts:rows = 10</nowiki>
| ?
|-
| [[field_cols|widget:atts:cols]]
| This directive specifies the number of columns for a text area input field (1 character = 1 column).  For example: <nowiki><br/>widget:atts:cols = 10</nowiki>
| ?
|-
| [[field_javascript_onchange|widget:atts:onchange]]
| This directive will cause the specified javascript function to be called with the value of the field whenever its value is changed (i.e. when you change the field and tab out of it).  For example: <nowiki><br/>widget:atts:onchange = ""doJsFunction();""</nowiki>
| ?
|-
| [[field_javascript_onclick|widget:atts:onclick]]
| This directive will cause the specified javascript function to be called with the value of the field whenever it is clicked.  For example: <nowiki><br/>widget:atts:onclick = ""doJsFunction();""</nowiki>
| ?
|}

===Helpful tutorials===

See the bottom of this page in the Getting Started tutorial for more details on the basic directives above:

[http://xataface.com/documentation/tutorial/getting_started/customizing Customizing Field labels, descriptions, and widgets]

This tutorial talks about how to use the javascript directives:

[http://xataface.com/documentation/how-to/custom_javascripts]",,en,0
visibility:fieldName,47,visibility:fieldName,"==Example==

<code>visibility:ConferenceID = hidden</code>

This will make the ConferenceID in the relationship list view disappear.",,en,0
tab,48,tab,"==tab directive of the fields.ini file==

[[toc]]

The ''tab'' directive of the [[fields.ini file]] specifies which tab of the record edit form a field should be displayed on.  Xataface supports multiple tabs on the edit form by way of this ''tab'' directive.  If no fields contain the ''tab'' directive then all fields are displayed in a single tab (named ''__main__'').

==Example 1: Placing address info on separate tab==

Consider the following ''people'' table: 
<code>
CREATE TABLE `people` (
    person_id int(11) not null auto_increment primary key,
    first_name varchar(32) not null,
    last_name varchar(32) not null,
    address varchar(100),
    city varchar(100),
    province varchar(100),
    country varchar(100),
    postal_code varchar(20)
)
</code>

We want to split the fields into two tabs:
* Personal Info
* Address Info

===Splitting form into tabs===
We'll do this in two steps.  We use the ''tab'' directive to assign all address-related fields to the ''address_info'' tab.  In the tables/people/fields.ini file:
<code>
[address]
    tab=address_info

[city]
    tab=address_info

[province]
    tab=address_info

[country]
    tab=address_info

[postal_code]
    tab=address_info
</code>

Now, when we load the edit form of the ''people'' table, we see two tabs:

* __main__
* address_info

<nowiki>
<img src=""http://media.weblite.ca/files/photos/Picture 9.png?max_width=640""/>
<img src=""http://media.weblite.ca/files/photos/Picture 10.png?max_width=640""/>
</nowiki>

''__main__'' is the name assigned to the default tab (for all fields that don't have a tab defined explicitly.


===Customizing the tab labels===

Next we will customize the tab labels by adding the following to the beginning of the [[fields.ini file]]:
<code>
[tab:__main__]
    label=""Personal Information""

[tab:address_info]
    label=""Address Information""
</code>

<nowiki>
<img src=""http://media.weblite.ca/files/photos/Picture 11.png?max_width=640""/>
<img src=""http://media.weblite.ca/files/photos/Picture 12.png?max_width=640""/>
</nowiki>


===Reordering the tabs===

If we want to reorder the tabs so that the ''address_info'' tab comes first, we would just reorder the definitions of the tabs:
<code>
[tab:address_info]
    label=""Address Information""

[tab:__main__]
    label=""Personal Information""
</code>

<nowiki>
<img src=""http://media.weblite.ca/files/photos/Picture 13.png?max_width=640""/>
</nowiki>

===Try This Example App===

You can try this tiny sample application out [http://dev.weblite.ca/tab_test here].",,en,0
Troubleshooting,49,Troubleshooting,"==Xataface Troubleshooting==

This document is intended to help Xataface developers through some of the most common issues.

[[toc]]

==All I get is a blank white screen!==

The most common issue mentioned in the forums is that an application comes up with a blank white screen in the web browser.  This can happen for a number of reasons but the most common reason is because PHP has encountered a fatal error and your PHP installation is not set up to display errors.  

The first step to troubleshooting this problem must be to find out what the error is.  You can do that in one of the following ways:

# Check your Apache error log if you know where it is.  One common location on many linux installations is <code>
/var/log/httpd/error_log
</code> but your system may have it located elsewhere.  If you cannot find your error log, continue to the next option.
# Turn on the ''display_errors'' flag in your ''php.ini'' file.  I.e., in your ''php.ini'' file, find where it says <code>
display_errors Off
</code> and change it to <code>
display_errors On
</code>.  After this is done, restart your apache webserver.  If you don't know where your ''php.ini'' file is located see the section later in this document on locating your ''php.ini'' file.  If you don't have access to your php.ini file, move on to the next option.
# In your application's ''.htaccess'' file, add the following directives to enable displaying errors:<code>
php_flag display_errors on
</code> .  Note that this method will only work if your apache config file allows you to override these values at the directory level.  If you still get a blank white screen after this, continue to the next option.
# At the beginning of your application's index.php file, add the following:<code>
<?php
error_reporting(E_ALL);
ini_set('display_errors', 'on');
</code> .  Note that if the error occurs in the parsing or compiling of your PHP files you will still get a blank screen.  But this will at least display runtime errors on the page.

Once you can see the error messages that caused the blank white screen you are in a much better position to solve the problem.

==Locating your php.ini file==

Locating your ''php.ini'' file is actually quite easy.  The quickest way is to create a php script with the following contents:
<code>
<?php
phpinfo();
</code>
then navigate to this page in your web browser.  This look at the line where it says the ''php.ini file''.  It will list the path there.",,en,0
__field__permissions,50,__field__permissions,"This method can be used to set the default permissions for all fields in a designated table, when specified in that table's delegate class. It comes in handy in situations when you want to deny access to all fields except for those designated, rather then specifying each field to deny individually. For example, to revoke edit permissions from all fields but one, the user must first have edit permissions to the table overall, otherwise the Edit tab/action will not appear. Then, use this __field_permissions method to revoke edit permissions from all fields. Finally, use the fieldname__permissions method (see below) to allow access to only those fields needed.

=== Also See: ===

* [[How_to_granulate_permissions_on_each_field]]
* [[fieldname__permissions]]",,en,0
Email,54,Email,"==Xataface Email Module==

[[toc]]

The Xataface Email module allows you to convert your database into a mailing list so that you can easily send email to any found set of records, as long as the records contain an email address to send to.

==Features==

* Send email to any found set.
* Mail merge macros
* HTML Email support (uses NicEdit WYSIWYG editor for email editing).
* Opt out support (allows recipients to opt out of your mailing list).

==Requirements==

* Xataface 1.0+
* MySQL 4.1+
* PHP 5+

==Download==

https://sourceforge.net/project/platformdownload.php?group_id=253820

==Installation==

# Download and extract Email directory so that it is located inside the xataface/modules directory (i.e. xataface/modules/Email)
# Add the following to the ''[_modules]'' section of your application's conf.ini file:<code>
modules_Email=""modules/Email/Email.php""
</code>
# Configure the [email] action in your application's actions.ini file.  See the section called 'Configuration' for configuration details.
# Add a line to your crontab file to send out pending email periodically.  The line should look like:<code>
* * * * * /usr/bin/php <cronpath> <indexpath> <indexurl> mail

where <cronpath> is the absolute path to the cron.php script.
      <indexpath> is the absolute path to your application's index.php script.
      <indexurl> is the absolute url to your application's index.php script.
		
For example:

* * * * * /usr/bin/php /var/www/xataface/modules/Email/cron.php \
		/var/www/myapp/index.php \
		http://example.com/myapp/index.php \
		mail
</code> If you want to see what this line should be like for your server, you can simply point your browser to the email_install action of your application (i.e. http://example.com/yourapp/index.php?-action=email_install) and it will generate this line to copy and paste into your crontab.  Note that the /usr/bin/php portion of this line may vary according to your environment.  It represents the path to your PHP binary.
# That's it!  You're ready to send email.  See the ''Usage'' section to see how to send email from your application.

==Configuration==

Though the email action may work out of the box, you will likely have to configure it to work the way you want.  Some examples of things you will want to configure include:

# Limit the email action to only be available for certain tables.
# Apply permissions to the action so that only administrators can send email.
# Set the name of the column that contains email address (default is 'email').
# Change the name of the table that is used to store sent email messages.

===Overriding the ''[email]'' action===

The first thing you need to do to configure the email action is override it in your appliation's actions.ini file.  You can do this by adding the following to your [[actions.ini file]]:
<code>
[email > email]
</code>

Now any directives you add in this section will override the email action.

====Examples:====

=====Limiting email action to certain tables=====

In your appliation's [[actions.ini file]]:
<code>		
[email > email]
    condition=""$query['-table'] == 'Pledge' or $query['-table'] == 'User'""
</code>


=====Limiting email action by permission=====

By default your users require the ''email'' permission in order to have access to the email form.  This permission is not included with any roles by default so you'll need to extend any roles that you want to have access to the email access and explicitly add the ''email'' permission.  The exception to this rule is if you have assigned your users the ''Dataface_PermissionsTool::ALL()'' permissions in your ''getPermissions()'' method.

Suppose you want the ''READ ONLY'' role to have access to the email action, you could add the following to your application's [[permissions.ini file]]:
<code>
[READ ONLY extends READ ONLY]
     email=1
</code>   			

=====Changing the name of the email address column=====

By default, the Email module will try to guess which column contains the email address for a table.  Generally it looks for a column named ''email''.  You can override this setting to explicitly tell the module which column contains the email address by overriding the ''email_column'' directive of the ''email'' action in your application's [[actions.ini file]]:
<code>
[email > email]
    email_column = ""emailAddress""
</code>

=====Changing the name of the table that stores the sent email====

Xataface automatically stores each sent email for your records.  By default it stores these emails in a table named ''newsletters''.  You can override this table name with the ''email_table'' directive in your application's [[actions.ini file]].  This table will be automatically created by Xataface when email is sent out.
<code>
[email > email]
    email_table = ""newsletters""
</code>
	
=====Altogether=====

<code>
[email > email]
    condition=""$query['-table'] == 'Pledge' or $query['-table'] == 'User'""
    permission=email
    email_column = ""emailAddress""
    email_table = ""newsletters""
</code>


==Usage:==

===Sending Email to All Records of a Table===

# Navigate to a table for which your email module is enabled, and click on the ''list'' tab.
# Click on the ""Email"" icon in the upper right corner.  This should display an email form.<nowiki>
<img src=""http://media.weblite.ca/files/photos/email_icons.png""/>
</nowiki>
# Fill in the email form and press Save.<nowiki>
<div><img src=""http://media.weblite.ca/files/photos/email_form.png?max_width=500""/></div>
</nowiki>
# You should receive a message saying that the email has been queued for delivery.  Your cron script will automatically begin sending emails the next time around.  So make sure that you have yoru cron script set up properly.

===Opting Out of the Email List===

If you have received an email that was sent via the email module you can easily opt out of the mailing list by clicking on the link at the end of the email.  This link will bring you to a webpage that asks you to confirm that you no longer wish to receive email from this list.



==Using a View to add Email Action to Related Record List==

You can simulate a many-to-many [[relationships.ini file|relationship]] in a mysql view by creating a view with all possible combinations. 

e.g. If you have a Many to Many [[relationships.ini file|relationship]] between books and authors your [[relationships.ini file|relationship]] from the books table might be something like: 

<code>

[authors] 
__sql__ = ""select * from authors a inner join book_authors ab on a.author_id=ab.author_id where ab.book_id='$book_id'"" 

</code>

And your relationship from the authors table would be something like: 
<code>
[books] 
__sql__ = ""select * from books b inner join book_authors ab on b.book_id=ab.book_id where ab.author_id='$author_id'"" 
</code>

Now if our goal was to be able to send email to all authors of a particular book (i.e. send to the authors relationship), we could create a view: 
<code>
create view book_authors_maillist as 
select * from authors a inner join book_authors ab on a.author_id=ab.author_id 
</code>

This view can now be used in xataface like a regular table (if you add a [[fields.ini file]] for it and [[Key|mark the primary key columns]]). If you wanted to find all authors for a certain book you would just do: 

index.php?-action=list&-table=book_authors_maillist&book_id=10 

So you could easily create an action in the [[actions.ini file]] that would like to the mail action on the book_authors_maillist table with the parameters you wanted. 

e.g. 

<code>
[related_authors_mail] 
    category=related_list_actions 
    url=""{$site_href}?-action=email&-table=book_authors_maillist&book_id={$record->val('book_id')}"" 
    icon=""{$dataface_url}/images/mail_icon.gif"" 
    url_condition=""$record"" 
    condition=""$query['-table']=='books' and $query['-relationship'] == 'authors'"" 
    permission=""email"" 
</code>


This action would send mail to only the authors related to the current books. It would be made available in the icons in the upper right on the related list view of only the authors of a book.

===Mail Merge===

The 'Embed Macro' shown above the email form lists the fields which may be included in the email.

Say you have a field called 'email_firstname'. You would type this into the message area like this: %email_firstname%

When the email is sent, this is substituted for the record of that recipient.

Eg. Dear %email_firstname% would be received by email as Dear Tom

If the particular record of the field you are merging is blank, then (in this case) the first name will not be shown.","Email,Email module,Sending Email,Maillist",en,0
fieldgroup_template,51,fieldgroup_template,"==Using a custom template for a field group on the edit form==

[[toc]]

Xataface allows you to partition your fields into ''groups'' so that similar fields are grouped together on the edit form.  The default layout of the fields remains simply vertical, but you can customize this layout (on a per-group basis) by creating a custom template and then assigning this template to the field group with the ''template'' directive.


===Example===

For example, in your [[fields.ini file]] if you wanted to group your address fields together you might have:
<code>
[fieldgroup:address]
    label=""Address Information""
    template=""AddressInformationGroup.html""

[address_1]
    group=address

[city]
    group=address

[state]
    group=address
</code>

Then you would add the a template named ''AddressInformationGroup.html'' to your application's ''templates'' directory to display how the fields are laid out:
<code>
<table width=""100%"">
    <tr><th>Address 1:</th>
    <td>{$elements.address_1.html}</td>

    <th>City:</th>
    <td>{$elements.city.html}</td>

    <th>State:</th>
    <td>{$elements.state.html}</td>
    </tr>
</table>
</code>
This would display all of the fields in this group in a single row (horizontally) instead of vertically.

Note that this is an over-simplified example that doesn't take account for display error messages, required notices, grouped fields, and other information that you can obtain from the {$elements} array.",,en,0
How_to_Add_Custom_Sections_to_View_Tab,52,How_to_Add_Custom_Sections_to_View_Tab,"==How to Add Custom Sections to the View tab==

[[toc]]

The ''View'' tab is intended to give the user a detailed view of the contents of a record.  By default it shows the values of each non-empty field grouped into their appropriate field groups.  It also shows the most recent 5 related records from each relationship in the record.  You can also add your own sections by implementing the [[section__xxx]] method of the delegate class.

==Example 1: A ""Hello World"" Section==

We'll start by adding a simple section that simply displays ""Hello World"" to the user.  In the delegate class for your table, add the following method:
<code>
function section__hello(&$record){
    return array(
        'content' => 'Hello World!!!',
        'class' => 'main'
    );
}
</code>

Now if you reload our application and click on the ""View"" tab for any of the records in the database, you'll notice a section labelled ''hello'' with the text ''Hello World!!!'' in it.

Let's dissect the above code so that we can better understand what is going on here.

# The function ''section__hello()'' defines a section named ''hello''.  If you wanted to define a section named ''foo'' you would call the function ''section__foo()''
# This function returns an array with the keys ''content'', and ''class''.
# The ''content'' key points to the actual HTML content of the section.  In this case it is simply the text ''Hello World!!!''.
# The ''class'' key defines where the section should be displayed.  It accepts values of ''left'' and ''main'' only.  If it is set to ''left'', then the section will be displayed in the left column.  A value of ''main'' indicates that it should be displayed in the main column.

===Customizing the Section Label===

''hello'' is a boring label, so let's add our own custom label by adding the ''label'' key to the array returned by our method:
<code>
function section__hello(&$record){
    return array(
        'content' => 'Hello World!!!',
        'class' => 'main',
        'label' => 'Message of the Day'
    );
}
</code>

Now if you load the view tab of your application, you'll notice that the section has a heading ""Message of the Day"".

===Customizing the Section Order===

A section can also specify an ''order'' attribute to define the order in which this section should appear.  It defaults to 0 which may cause the section to appear at the top of the view tab.  You can push it to the bottom of the view tab by assiging a higher number to the ''order'' attribute:
<code>
<code>
function section__hello(&$record){
    return array(
        'content' => 'Hello World!!!',
        'class' => 'main',
        'label' => 'Message of the Day',
        'order' => 10
    );
}
</code>

Now if you reload the view tab you'll notice that the section has moved to the bottom of the page.",,en,0
fieldname__permissions,53,fieldname__permissions,"==fieldname__permissions() method==

[[toc]]

The fieldname__permissions() methods will allow you to define custom permissions on a particular field in the [[delegate class]].  For example to specify permissions on a field named ''foo'' you would define the ''foo__permissions()'' method, and to define permissions on a field named ''role'' you would define the ''role__permissions()'' method.


==Example #1==

(Note this example needs to be refined to be more clear)

<code>
function approval_level__permissions(&$record){
	return array('edit'=>0); //this is will merge with what the permissions for the normal record
}
</code>

Here we are targeting the ''approval_level'' field of the [[delegate class]].  The permissions method takes a return value an array of permissions.  So for example:

<code>
$permissions['new'] = 0;
$permissions['edit'] = 0;
</code>

Would be an example of an array of permissions which the key being the permission name and the value being a boolean to specify whether they have (1) or don't (0) have permissions to that field.  We don't have to specify a complete array of permissions (ie. permission of edit, new, readonly, etc, etc), but rather only the ones we want specifically.  The reason being that the permissions array in the return value gets merged with the permissions that this record normally gets from the record permissions.

So if the record normally gives the permissions new=0, edit=1.  Then the return value from approval_level will merge with the original permissions to produce an array like this:

<code>
$permissions['new'] = 0;
$permissions['edit'] = 1;
</code>

=== Also See: ===

* [[How_to_granulate_permissions_on_each_field]]
* [[__field__permissions]]",,en,0
blob,55,blob,,,en,0
struct,56,struct,,,en,0
Creating_a_Dashboard,57,Creating_a_Dashboard,"==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'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 ''dashboard'' 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 ''list'' tab of the ''bibliographies'' table.  This isn'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 ''new record'' 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 ''strategies'' section.

===Step 1: Create a dummy ''dashboard'' 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 ''_tables'' section of the [[conf.ini file]] and thus be the default table when users visit our application.

<code>
CREATE TABLE dashboard (
    dashboard_id int(11) not null auto_increment primary key
);
INSERT INTO dashboard values (1);
</code>

===Step 2: Make ''dashboard'' table default===

We now modify the conf.ini file to list the ''dashboard'' table first:
<code>
[_tables]
    dashboard=Dashboard
    bibliographies=Bibliographies
</code>

===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 ''actions/dashboard.php'' file of our application, and looks like:

<code>
<?php
class actions_dashboard {
    function handle(&$params){
        $bibs = df_get_records_array('bibliographies', array());
        df_display(array('bibliographies'=>$bibs), 'dashboard.html');
    }
}
</code>

All this does is loads the ''bibliographies'' records owned by the current user. Elsewhere we are using security filters so that the user can only see ''his'' bibliographies, which is why we don't need to specify any query here in the ''df_get_records_array'' function.

It then passes those bibliographies to the ''dashboard.html'' template that we create next.

====Creating the Action's Template====

The template for our action is located in the ''templates/dashboard.html'' file:
<code>
{use_macro file=""Dataface_Main_Template.html""}
    {fill_slot name=""main_column""}
        <h1>Welcome to the BibTeX Publication Management System (BPMS)</h1>
        
        <p>This system allows you to manage your publications and publish
        them on the web.  Some common actions you may perform with this system
        include:
            <ul>
                <li><img src=""{$ENV.DATAFACE_URL}/images/add_icon.gif""/>
                    <a href=""{$ENV.DATAFACE_SITE_HREF}?-table=bibliographies&-action=new"">
                        Create New Bibliography</a>
                </li>
                <li><img src=""{$ENV.DATAFACE_URL}/images/edit.gif""/> 
                   Edit existing bibliography: 
                   <select onchange=""window.location.href=this.options[this.selectedIndex].value"">
                    <option value="""">Select ...</option>
                    {foreach from=$bibliographies item=bibliography}
                        <option value=""{$bibliography->getURL('-action=edit')}"">
                            {$bibliography->getTitle()}
                        </option>
                    
                    {/foreach}
                </select>
                </li>
                <li><img src=""{$ENV.DATAFACE_URL}/images/file.gif""/> 
                    Embed your bibliography in a webpage:
                    <select onchange=""window.location.href=this.options[this.selectedIndex].value"">
                    <option value="""">Select ...</option>
                    {foreach from=$bibliographies item=bibliography}
                        <option value=""{$bibliography->getURL('-action=view')}#embed"">
                            {$bibliography->getTitle()}
                        </option>
                    
                {/foreach}
                </select>
                </li>
                
            </ul>
    {/fill_slot}
{/use_macro}
</code>

A few key things to notice in this template:

# It extends the ''Dataface_Main_Template.html'' template placing its content in the ''main_column'' 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's base url and create links to the desired common actions.
# It provides a direct link to the ''new bibliography record'' 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'll require the 'view' permission for this action, by adding the following to the actions.ini file:

<code>
[dashboard]
    permission=view
</code>


===Step 4: Specify permissions===

We still want to specify permissions for our ''dashboard'' table to ensure that only logged in users can access the dashboard.  So we create a delegate class for the ''dashboard'' table at ''tables/dashboard/dashboard.php'' with the following contents:

<code>
<?php
class tables_dashboard {
    function getPermissions(&$record){
        if ( getUser() ){
            return Dataface_PermissionsTool::ALL();
        }
        return null;
    }
}
</code>

'''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.'''

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 ''dashboard'' the default action for the ''dashboard'' table===

Now we just have one more detail that needs to be taken care of.  We want the ''dashboard'' action to be the default action for the ''dashboard'' table only.  By default we would see the ''list'' action which isn'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 ''dashboard'' action if they access the ''dashboard'' table.  We define a beforeHandleRequest() method in our conf/ApplicationDelegate.php (the application delegate class) file for this purpose:

<code>
<?php
class conf_ApplicationDelegate {
    
...
    function beforeHandleRequest(){
        ...
        $app =& Dataface_Application::getInstance();
	$query =& $app->getQuery();
	if ( $query['-table'] == 'dashboard' and ($query['-action'] == 'browse' or $query['-action'] == 'list') ){
	    $query['-action'] = 'dashboard';
	}
        
        
    }
    
    ...
}
</code>

This simply checks to see if the table is ''dashboard'' and changes the current action to ''dashboard'' 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 ''Dashboard'' 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.

<nowiki>
<img src=""http://media.weblite.ca/files/photos/pub-dashboard.png?max_width=640""/>
</nowiki>",dashboard,en,0
Selected_Records_Actions,58,Selected_Records_Actions,"==Creating a Custom ''Selected Records'' Action==

[[toc]]

If you view the ''list'' tab in any of your Xataface applications, you'll notice that there is a checkbox next to each row of the list, and there are a number of actions listed at the bottom of the list that you can perform on the selected records.  Xataface comes pre-built with only a few of these actions:

# Delete selected
# Update selected
# Copy selected

However it is quite easy to add your own actions here that are performed on selected records.  This article describes exactly how to do this.

===What is a ''Selected Record'' action?===

A ''Selected Record'' action is no different than any other action in Xataface, except that it is meant to act on the records that have been selected in the list tab.

==Example Action:  Approve Records==

Consider a news site where news stories are automatically imported into the database en masse, but each news story has a field ''approved'' to indicate whether the store has been approved to appear on the site yet.   The usage pattern of this application involves a lot of looking through lists of news stories and approving them.  Therefore it would be convenient if the user could just select the rows that he wants to approve and click a button to approve them all.

Out of the box Xataface would allow the user to select the records, click ''update selected records'', then update them all via the ''update selected records'' form.  But avoiding this extra step will improve usability greatly.

===Step 1: Design the Action===

First we need to specifically decide how our action will work.  In this case, the flow goes as follows:

# User selects the news items they want to approve.
# User clicks the ''Approve Selected'' button. (to be created)
# Our action approves the selected records.
# User is automatically redirected back to the list tab with a message stating how many records were successfully approved, and whether there were any errors.

===Step 2: Gather Our Tools===

Before we actually create the action, let's look at a few tools that we'll be using from the Xataface framework to make this happen.

# In the [[actions.ini file]], the ''[[selected_result_actions]]'' category is reserved for actions that act on selected records of the list tab.  E.g.<code>
[delete_selected]
    ...
    category=selected_result_actions
    ...
</code>
# The [http://dataface.weblite.ca/df_get_selected_records df_get_selected_records()] function returns an array of [http://dataface.weblite.ca/Dataface_Record Dataface_Record] objects that represent the rows that were selected to initiate the action.  E.g.<code>
$app =& Dataface_Application::getInstance();
$query =& $app->getQuery();
$records = df_get_selected_records($query);
foreach ($records as $record){
    ...
}
</code>
# The [http://dataface.weblite.ca/checkPermission Dataface_Record::checkPermission()] method allows us to see if the current user has access to a specific permission on the given record.  We'll use this method to ensure that the user has permission to approve the news record. E.g.<code>
if ( !$record->checkPermission('edit', array('field'=>'approved')) ){
    return PEAR::raiseError(""You don't have permission to edit the approved field for this record."");
}
</code>
# The Xataface will pass the redirect URL where your action should send the user upon completion of the action as the ''--redirect'' attribute of the ''POST'' variables.  This value is base64_encoded so you'll need to decode it before redirecting.  E.g.:<code>
if ( @$_POST['--redirect'] ) 
    $url = base64_decode($_POST['--redirect']);
$url .= '&--msg='.urlencode($updated.' records were deleted.');
header('Location: '.$url);
exit;
</code>

===Step 3: Create the Action===

We will call our action ''approve_news'' so we'll place it in the ''actions/approve_news.php'' file of our application:
<code>
<?php
class actions_approve_news {
    function handle(&$params){
        // First get the selected records
        $app =& Dataface_Application::getInstance();
        $query =& $app->getQuery();
        $records =& df_get_selected_records($query);

        $updated = 0;  // Count the number of records we update
        $errs = array();   // Log the errors we encounter

        foreach ($records as $rec){
            if ( !$rec->checkPermission('edit'), array('field'=>'approved')) ){
                $errs[] = Dataface_Error::permissionDenied(
                    ""You do not have permission to approve '"".
                    $rec->getTitle().
                    ""' because you do not have the 'edit' permission."");
                continue;
            }
            $rec->setValue('approved', 1);
 
            $res = $rec->save(true /*secure*/);
            if ( PEAR::isError($res) ) $errs[] = $res->getMessage();
            else $updated++;
            
        }
        
        if ( $errs ){
            // Errors occurred.  Let's let the user know.
            // The $_SESSION['--msg'] content will be displayed to the user as a message
            // in the next page request.
            $_SESSION['--msg'] = 'Errors Occurred:<br/> '.implode('<br/> ', $errs);
        } else {
            $_SESSION['--msg'] = ""No errors occurred"";
        }
        

        $url = $app->url('-action=list');   // A default URL in case no redirect was supplied
        if ( @$_POST['--redirect'] ) $url = base64_decode($_POST['--redirect']);
        $url .= '&--msg='.urlencode($updated.' records were deleted.');

        // Redirect back to the previous page
        header('Location: '.$url);
        exit;
    }
}
</code>

===Step 4: Add the action to your actions.ini file===

The actions.ini file allows us to specify how and where this action is used, and by whom.  We can specify permissions that are required to perform the action, conditions that are required to display the action, confirmation messages that are to be displayed to the user when they are about to perform the action, and more.  Our [[actions.ini file]] entry looks like:

<code>
[approve_news]
    label=""Approve""
    description=""Approve selected records""
    permission = edit
    category=selected_result_actions
    confirm=""Are you sure you want to approve the selected records?""
    icon=""${dataface_site_url}/images/approve.gif""
    condition=""$query['-table'] == 'news'""
</code>

This should be fairly straight forward.  The only special items here are the ''category'' and ''confirm'' directives.  The ''condition'' directive tells Xataface that this action should only be shown for the ''news'' table. 

The ''confirm'' directive defines a confirmation message that should be displayed to the user when they attempt to approve records.

The ''icon'' directive allows you to specify the path to an icon to display for the action.  In our case we have an icon located in the images directory of our application.

===Step 5: Trying it out===

Now when we go to the ''list'' tab of the ''news'' table there is an ''Approve'' button along the bottom where it says ""With Selected"".  You we can click on this button to approve any of the selected rows.


	",,en,0
no_access_text,59,no_access_text,"Whenever the NO_ACCESS permission is given for a field, normally the text NO ACCESS appears.  But we might want to display another text.  Here is an example of the text subscribe is used instead of NO ACCESS whenever the NO_ACCESS permissions is given.

<code>function no_access_text(&$record){
		return ""Subscribe"";
	}
</code>",,en,0
widget:type_textarea,60,widget:type_textarea,,,en,0
lookup,61,"The Lookup Widget","Return to [[widget:type]] page to see list of all widget types.
Back to [[fields.ini file]] to see other fields.ini directives.

[[toc]]

===Synopsis===

The lookup widget allows users to look a record from another table to insert into the field.  It is like a select widget except that it doesn't use a vocabulary.  Instead you just specify a table on which it should search using the widget:table directive.  In order to use the lookup widget to edit a field, you should set the [[widget:type]] directive of the [[fields.ini file]] for the field to '''lookup''.  I.e.
<code>
[fieldname]
    widget:type=lookup
    widget:table=mytable
</code>

'''Note that the lookup widget requires the [[widget:table]] directive to be set to the target table of the lookup or it will not work properly.'''

===Required Directives===

The following [[fields.ini file]] directives are required to accompany the field definition if a lookup widget is used:

{| class=""listing listing2""
|-
! Name
! Description
! Version
|-
| widget:table
| The name of the table in which the lookup widget should look up related records.
| 1.0
|}


===Optional Directives===

The following additional optional directives may be used to customize the behaviour of the lookup widget:

{| class=""listing listing2""
|-
! Name
! Description
! Version
|-
| widget:filters:-limit
| Sets the number of records that are shown by default in the lookup widget.  Default is 30 if this is omitted. E.g.<code>widget:filters:-limit=100</code> to show 100 records at a time.
| 1.0
|-
| widget:filters:-sort
| Specifies the columns to sort the results on. E.g. <code>widget:filters:-sort=category_name asc, year desc</code>
| 1.0
|-
| widget:filters:*
| Any valid Xataface directive can be used to filter the results by specifying widget:filters:param  (where ""param"" is a valid Xataface GET parameter, which could include a column name to filter results on, or other filter directives). <code>widget:filters:country=Canada</code> To only show results with Country=Canada.
| 1.0
|-
| widget:filters:*=$*
| Dynamic filters.  Causes the options in the record browser to be filtered on the value of another field in the form.  e.g. <code>widget:filters:country_id=""$country_id""</code> would show only results with records having country_id matching the value of the 'country_id' field in the current form.
| 1.3.1
|}

See [[URL Conventions]] for an overview of the types of GET parameters Xataface can take.  Any GET parameters that manipulate a query can be used with the widget:filters:* directive to modify the query results that are shown in the lookup widget.


===Example===

In this example we have a field named appointee that is supposed to reference the contacts table.  So in the [[fields.ini file]] we would have:

<pre>
[appointee]
    widget:type=lookup
    widget:table=contacts
</pre>

Initially we just have a little find icon next to the field. If the user clicks it, a dialog pops up enabling them to search for the contact that they want:

[[Image:http://media.weblite.ca/files/photos/Picture%2023.png?max_width=640]]


===Additional Tips===

Although the lookup widget does not use a vocabulary as indicated in the Synopsis above, it is still useful to define a vocabulary in the fields.ini file for this field. The reason is because the lookup widget is only used with the edit action, where you are inserting or editing data into the field. However, it is not used to the display the data in the view or list actions. Therefore, you must still have a vocabulary defined to properly display these values.

In order to customize the display of the lookup widget's select list, you must edit the delegate class for the table which is referenced by the widget:table directive. There are two important points to note:

# The items in the selection list are formatted based on the getTitle(&$record) delegate class function if it is defined. However, ...
# The Search box will search on text in VARCHAR and TEXT fields. If you need to search for data in numeric fields, you can create a grafted field using a function such as CONCAT() to display numbers as text.

Links:
* [http://xataface.com/forum/viewtopic.php?f=4&t=6723 Lookup widget on view with compound primary key]","lookup widget, widget:filters, widget:-filters:limit, widget:table",en,0
Customizing_the_look_and_feel_of_a_row_or_a_cell,62,Customizing_the_look_and_feel_of_a_row_or_a_cell,"==How to customize the look and feel of elements in the list view==

===Create a method in a delegate class===

In the delegate class, the method ''css__tableRowClass'' is implemented, like in this example :

<code>class tables_journal_interventions {
function css__tableRowClass(&$record){
    if ( !$record->val('fermeture')){
        return 'intervention_close';
    }
    else return '';
} 
}
</code>

Here the function tests a condition : is there a value in the field ''fermeture'' ?

===Add the class in a CSS stylesheet===

Now the class is created in a CSS stylesheet.

<code>td.intervention_close {
        background-color: #FFE6E6 !important;
    } </code>

This is a class for each cell, the <td> tag. The ''!important''  attribute is added to be sure that this information has precedence over all the others. It is better to add this class in a [http://xataface.com/documentation/how-to/custom_javascripts custom CSS stylesheet].

===Remarks===

Beware that some versions of IE don't respect the background-color property on the <tr> tag, so it is probably better to write:

<code>

    tr.intervention_close td {
        background-color: #FFE6E6;
    }</code>

i.e. to apply the background color to the individual cells. ",,en,0
How_to_granulate_permissions_on_each_field,63,How_to_granulate_permissions_on_each_field,"==How to granulate permissions on each field==

To reach this aim, there is the method fieldname__permissions to place into the delegate class of the table. 

===Getting the role===

First it is necessary to know the user's role. For this, the method getUser() is added in the class :
<code>function getUser(&$record){
  $auth =& Dataface_AuthenticationTool::getInstance();
    $user =& $auth->getLoggedInUser();
return $user;
}</code>


===Setting up the permissions for each field===

Next, the permissions are built for each column or field where they are needed, like in this example where the method name is formed with the field name, followed by 2 underscores then by ''permissions'' :

<code>function fieldname__permissions(&$record){

$the_user =$this->getUser($record);
$user=$the_user->val('identifiant');
if ( !$user) return Dataface_PermissionsTool::NO_ACCESS();

    if ( $user=='demande' ){
        return Dataface_PermissionsTool::ALL();
    } elseif ($user=='admin'){
 return Dataface_PermissionsTool::ALL();
}
else {
        return Dataface_PermissionsTool::READ_ONLY();
    }
}</code>


=== Also See ===

* [[viewable_editable_fields]] - How to make a field editable for some users and only viewable for some other users  
* [[no_access_text]] - Replace the default NO ACCESS permission text with another text.
* [[__field__permissions]] - Returns the default permissions for a field of a given record.
* [[Delegate_class_methods#toc5|Permissions]] - other Delegate class methods",,en,0
LDAP_or_Active_Directory,65,"How to authenticate users with LDAP or Active Directory","[[toc]]

It is often easier to use the existing LDAP or Active Directory to authenticate users in Xataface than to create a new password for every user in the table users.

===In the conf.ini===

In the conf.ini file, in the [auth] part, you need to add your LDAP or AD configuration data :

<code>[_auth]
auth_type=ldap
users_table = xata_users
username_column = id
	ldap_host = ""xxx.xxx.xxx.xxx""
	ldap_port = ""389""
	ldap_base = ""OU=blabla,DC=blablabla""</code>

Here in the table users, you need the login but the password can be just ''PASS'', because the password will be fetched into the LDAP base.
You need to add the [http://weblite.ca/svn/dataface/modules/Auth/ldap/trunk/ auth module] in the conf/modules directory.

===See Also===

* [[authentication]] - Overview of Authenthentication features in Xataface","LDAP,Active Directory,Authentication",en,0
How_to_authenticate_users_with_LDAP_or_Active_Directory,64,How_to_authenticate_users_with_LDAP_or_Active_Directory,"==How to authenticate users with LDAP or Active Directory==

",,en,0
table,66,table,"When using widget:type table, it will store the data as XML.

So the field type must be TEXT (or varchar... but text is better). You can decide which columns you want in the table by creating sub-fields in your fields.ini file as follows:

Suppose you want a column called 'name' and a column called 'url'

<code>
[myfield]
widget:type=table
[myfield:name]
[myfield:url]
</code>

Now when you access the stored value using the Dataface API, the value of myfield will be stored as an array of associative arrays. e.g. 

<code>
foreach ( $record->val('myfield') as $vals){ echo $vals['name'].' -- '.$vals['url']; }
</code>",,en,0
grid,67,grid,"==widget:type = grid==

Suppose we have two tables, tbl_organisation and tbl_individuals, in the edit view for a record in the organisations table (tbl_organisations) we also want to be able to view and edit the individuals within this organisation we can use widget:type=grid

In the /tables/tbl_organisation/fields.ini we create a transient field by adding:

<code>
[Individuals]
widget:label = ""Individuals""
transient=1
relationship=individuals
widget:type=grid
widget:columns=""ind_firstname,ind_lastname,ind_tel""
</code>

The above assumes we have a relationship entry in our /tables/tbl_organisation/relationships.ini that looks like this:

<code>
[individuals]
__sql__ = ""SELECT * FROM tbl_individual WHERE org_id='$org_id'""
</code>

The fields.ini will show the three columns shown in widget:columns from the table tbl_individual

Correct permissions need to be set to enable editing and deletion etc of these records.",,en,0
relationship,68,"The relationship fields.ini directive","[[fields.ini file|Return to fields.ini file directives]]

[[toc]]

===Synopsis===

Certain types of widgets (e.g. grid (v1.0) and checkbox (v1.2)) support the relationship directive which allows them to effectively add/remove records from a specified relationship.  This directive only works with transient fields.

===Example 1: Checkboxes to add/remove categories===

(Note: This example requires Xataface 1.2 or higher to work)

Suppose we have a database that keeps track of courses and the branch of research that they belong to.  A course can be part of multiple branches.  We want to be able to select the branches that a particular course belongs to on the edit form for that course using checkboxes.

Table Structure:
<code>
courses:
   course_id : int (primary key)
   course_title : varchar

branches:
   branch_id : int (primary key)
   branch_name : varchar
   branch_description: text

course_branches:
   course_id : int
   branch_id : int
</code>

Relationship definition:  (from the tables/courses/[[relationships.ini file]]):
<code>
[branches]
    course_branches.course_id=""$course_id""
    course_branches.branch_id=branches.branch_id
</code>

Field definitions: (from tables/courses/[[fields.ini file]]):
<code>
[branches]
  transient=1
  relationship=branches
  widget:type=checkbox
</code>

Things to notice:
# This is a many-to-many relationship (hence the need for the course_branches join table.
# The [branches] field is a transient field.
# The relationship directive from the [[fields.ini file]] references our branches relationship that was defined in the [[relationships.ini file]].
# You can call the field anything that you like.  There is no need for it to have the same name as the relationship.  It just turned out that way in this example.  

===Example 2: Using a grid widget===

Let's modify example 1 slightly to use a grid widget instead of checkboxes.  The grid widget will allow us edit the records in a relationship using dynamic table.  It automatically uses the correct widget for each column of the table according to the definition in the target table's [[fields.ini file]].  Most of the definition can remain the same.  We only change the [[fields.ini file]] directive:

<code>
[branches]
  transient=1
  relationship=branches
  widget:type=grid
  widget:columns=""branch_name,branch_description""
</code>

In this case we are able to edit the branch name and description in each row of the grid.

===See Also===

* [[grid|The grid widget]]
* [[checkbox|The checkbox widget]]
* [[relationships.ini file|The relationships.ini file]]
* [[fields.ini file|The fields.ini file]]","grid widget, relationship, checkbox",en,0
checkbox,69,checkbox,"==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 ""Active"" 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:

<code>
[Active]
  widget:type=checkbox
</code>

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 '''categories''' which uses the '''categories''' [[valuelist]] to specify the different categories that can be checked at any given time.  Our [[valuelists.ini file]] might look like:
<code>
[categories]
    __sql__ = ""select id,name from categories""
</code>

And our [[fields.ini file]] looks like:
<code>
[categories]
    widget:type=checkbox
    vocabulary=categories
</code>
* Note that you don'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:
<code>
1
3
5
</code>
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 ""Categories"" relationship===

""""""(Note: This example requires Xataface version 1.2 or higher)""""""

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'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:

<code>
[categories]
    Books.Book_ID=""$Book_ID""
    Book_Categories.Category_ID=Categories.Category_ID
</code>

And our [[fields.ini file]] for the Books table might look like:
<code>
[categories]
    widget:type=checkbox
    transient=1
    relationship=categories
</code>
* 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'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 'repeating field'.  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.",,en,0
documentation_guide,70,"Documentation Guide","Xataface uses a wiki to manage its online documentation which can be edited by anyone.  All you have to do is [http://xataface.com/wiki/index.php?-action=login login with your forum username and password] ([http://xataface.com/forum/profile.php?mode=register register for the forum here]).  Then when you are browsing a page of the wiki, you'll see an 'Edit' tab along the top.  Click on this tab to start editing the page in your browser.  Wiki markup is a little simpler than HTML and a little more complex than plain text.  It is easy to get a handle on once you get started.  If you aren't sure how to format it exactly how you want, don't worry.  Someone may come by after you and improve on your formatting.  That's what the community approach is all about.

==The Documentation Team==

Join the Xataface documentation team to help participate in the planning of the documentation.  If you want to help out, contact [mailto:steve@weblite.ca Steve Hannah] and he'll add you to the documentation group where you can access the private documentation forums and meet the rest of the team.

==Using the Wiki==

The following is a brief guide in using the Xataface Wiki.  All following instructions assume that you are already [http://xataface.com/wiki/index.php?-action=login logged in] to the wiki.  You can use your forum username and password to login.

===Editing an Existing Page===

# Navigate to the page that you want to edit
# Click on the ""Edit"" tab along the top.
# Make changes to your page.
# Save the changes.

===Adding a New Page===

====Method 1: Add a link from an existing page===

# Navigate to an existing page that you want to link to your new page.
# Click on the ""Edit"" tab along the top.
# Somewhere in the content of the page, add a link to your new page (which doesn't exist yet), by adding the following markup<code>
[[The name of your new page]]
</code>
# Save your changes.
# Click on the ""view"" tab along the top and find the place where you added your link.  It should be displayed with a '?' right after it.  Click on the '?' and it will bring you to the ""new page form"".
# fill in the form with your page contents and click save.

====Method 2: Accessing new page form directly====

# Access the [http://xataface.com/wiki/index.php?-action=new&-table=wiki new page form] directly.


===Uploading Images===

Image can be uploaded at [http://media.weblite.ca The Web Lite Media Manager].  You'll need an account to access this site.  If you are a member of the documentation team you can request an account from [mailto:steve@weblite.ca Steve Hannah] so that you can upload images here.

Steps:

# Log into [http://media.weblite.ca the Web Lite Media Manager].
# Click on ""Add New File"" in the menu on the left.
# Select a name for the file, and browse to the image you want to upload in the file upload field.  You don't need to check any category boxes.  Press save.
# Click on the ""View"" tab for your newly uploaded image.
# Copy the embed code for the image from the ""Embed Code"" field.
# In the wiki page add the embed code where you want your image to appear as follows:<code>
[[Image:EMBED_CODE]]
</code> Where EMBED_CODE is the URL for the image as you copied and pasted out of the media manager.
# Save your changes.

===Uploading Video===

===Adding Source Code Snippets===","documentation wiki",en,
GettingStarted:Introduction,71,Introduction,"Web Lite is a simple framework for building data-driven web applications in PHP and MySQL. This section introduces some of the concepts and applications of Dataface.

To fully understand what Xataface is, we must first define a few key terms:

'''Framework''' - A set of software routines that provide a foundation structure for an application. Frameworks take the tedium out of writing an application from scratch. (From Answers.com)

'''Data-driven design'''- Designing an application around the data that it will store.

Xataface is a ''Framework'' in the sense that it is a set of classes and libraries that take the tedium out of writing web applications. It provides a simple web interface to a MySQL database enabling users to update, delete, and find data in the underlying database. The interface is targeted at secretaries and end-users as opposed to database administrators.

Xataface enables ''data-driven design'' because it allows developers to develop web sites by first designing the database that will be used to store the data on the website, and then design the pages used to display the data. The developer can focus on the data because he or she does not have to worry about having to build forms to update the data. If the requirements of the application change, the developer can simply add a field to the database table and all associated web forms will be updated automatically (because they are all dynamically generated using the database schema).


===Requirements===

* [http://php.net PHP] >= 4.3
* [http://mysql.com MySQL] >= 3.2.3

===Key Technologies===

* [http://pear.php.net PEAR class libraries] (HTML_QuickForm, etc...)
* [http://smarty.net Smarty Templating Engine]
* [http://plone.org Plone] Javascript and CSS style sheets

===Development Procedures===

# Identify the data that will need to be stored for a web site.
##[[Image:http://xataface.com/documentation/tutorial/getting_started/er-diagram.png]]
# Design the database using your favorite database administration program (e.g., PHPMyAdmin)
##[[Image:http://xataface.com/documentation/tutorial/getting_started/phpMyAdmin-1-small.gif]]
# Tell Xataface some DB connection info, and voila! You have an application:
##[[Image:http://xataface.com/documentation/tutorial/getting_started/new-record-form-1-small.gif]]

===Where to go from here===

This tutorial will teach you the basics of Xataface and how to construct a simple application using the Xataface. After reading this tutorial you will be ready to tackle some medium to large web sites with the help of the Xataface reference documentation. You are also encouraged to mail the [http://xataface.com/forum Xataface forum] if you have questions.","introduction requirements getting started",en,
GettingStarted:Why_Use_Xataface,72,"Why Use Xataface","==Why Use Xataface?==

Some simple examples similar to those that are frequently encountered by web developers, and how dataface can be used to acheive a solution.
As a web services developer in the Faculty of Applied Sciences at Simon Fraser University, I am frequently getting requests to build websites that are manageable by the site owner. Most of these requests also specify certain types of content that must be stored on the website, and much of this content needs to be n-ary (i.e., there will be multiple instances of each type of content). Let me give you an example.

===Example 1: Website for Faculty of Widgetry===

The Faculty of Widgetry needs a website to publish information about its undergraduate programs. It is important for them to be able to publish admission requirements, and program overviews for each program. It is also important to have course outlines and timetables for each course. The Faculty of Widgetry has 12 undergraduate programs and over 100 courses offered.

====Solution 1: Static HTML====

To build this web site using only static HTML pages using Dreamweaver or some other HTML editor would require at least 112 pages to be created (one for each course and program). However, once we recognize that there are only 2 types of pages required (one for courses and one for programs), we can reduce the task down to creating 2 templates and filling in the main content for each program and course individually. Most HTML editors have some templating ability so you can make changes to the template and have the changes propogated to all pages that use that template with the click of a button.

This works great, but courses are added frequently, and outlines are changed. Do you really want to receive requests to update all of these pages every time there are changes to make? (If your answer is 'yes', then you probably won't be interested in reading the rest of this tutorial). Whether the Dean of the faculty knows it or not, it is very important for the program assistants to be able to update these web pages on their own. To acheive these goals you can:

* Install Dreamweaver on the Program Assistants' computers, teach them how to use it, and allow them to perform updates.
* Install Contribute, which is a scaled down version of Dreamweaver to make it easier for the Program Assistants to edit the content.
* Use another solution that is equivalent to one of the above 2 solutions.

Installing Dreamweaver for each Program Assistant is a little overkill, and since it has the ability to do much more than just update content. In addition, Dreamweaver is really a developer's tool - not a secretary's tool, so it can be difficult to learn at first. The best reason NOT to install Dreamweaver on the Program Assistant's computer, however, is that it enables him/her to muck things up by accident (believe me, I has happened to me more times than I care to count).

Admittedly, Contribute is a viable option as it controls access to only certain portions of web pages to be edited, and it is targetted at secretaries (not developers) so it is easier to use. In fact, given the requirements for this web site (as stated above), this is a perfectly good solution. However you better hope that none of the following requirements are added:

* Each program web page should contain an up-to-date list of all of the courses required for the program, along with a link to the course outline for that course.
* Course outlines should be available in PDF format as well as HTML format.
* An index page showing all of the courses available should be added. This page must allow courses to be organized by program, course subject, or course number.
* Any other requirement that would have information formatted in more than one way.

If any of these requirements are likely to be added (EVER) then you would be well-advised to look into solutions that use a database back-end.

====Solution 2: Use a Content Management System (CMS)====

There are hundreds of content management systems available that will allow you to store and update content through the web (TTW). Some of them even have an assortment of add-ons that will allow you to store more specific types of information. Some good CMS's include Plone, Drupal, and Xoops. Suppose we want to develop the Faculty of Widgetry website using one of these CMS's. Any good CMS will allow you to create and edit HTML documents easily (without having to write any custom products). However, it is often the case that our documents require the content to be structured. For example, each program has some common data associated with it: Program Name, Admission Deadline, Program Description, Outline, Courses, etc... If we want to properly separate data from presentation, we would need to build a special content-type to store our programs. Most CMS's allow you to develop custom content-types using the underlying programming language and an API (Application Programming Interface). Some API's are easier to use than others and some are documented better than others. The common element is that each has its own proprietary interface for writing these add-ons.

If you are using a CMS and you are proficient in the creation of add-on content-types, then you will be able to build the Faculty of Widgetry website without great difficulty. However there are a number of reasons why you may choose NOT to use a CMS:

* Steep learning curve: Depending on the CMS it can be very time consuming and difficult to learn how to use and modify the CMS to suit you purposes.
* It is over-kill: Most CMS's are filled with features and modules that you will never need. In fact it can even be a pain to turn them off if you don't want them.
* You can get tied into the CMS: When you are using a CMS, you will start developing for the CMS. With all of your content in the CMS it may be difficult to migrate to a different solution later on. (The truth of this statement will vary for different CMS's). Choose your CMS carefully.

====Solution 3: Use an existing Application====

OK, OK, let's not get too carried away with trying to develop the website until we have checked the market to see if someone else has already done it better. Maybe there is already a PHP application that makes websites for Faculties easy. I mean, I can't be the first person that needed to build a website for a Faculty. In fact if you do a search or go to Hotscripts.com, you will probably find a handful of applications or scripts that almost do what you need. If you're lucky, maybe you can find an application that does exactly what you need (but frankly, I've never been that lucky). If you find one, maybe it's worth taking it for a test drive. But beware. Using a system that almost does what you need but is difficult to modify to your needs can be worse than building it by scratch. Make sure that you are able to modify the application to suit your needs exactly.

====Solution 4: Use PHP and MySQL====

If all we want to do is separate the data from the presentation and allow the Program Assistants to update data on the website, why not just design a MySQL database with the appropriate tables and fields to store the required data. In our case we will need 2 tables:

'''Programs''': 

* Fields:
** ProgramID : int
** ProgramName : varchar
** ProgramDescription: text
** AdmissionDeadline: date
** Outline_HTML : text
** Outline_PDF : blob


'''Courses''':
* Fields:
** CourseID : int
** CourseSubject : varchar
** CourseTitle : varchar
** CourseNumber : int
** ProgramID : int
** CourseDescription : text
** Outline_HTML : text
** Outline_PDF : blob


Now it's easy to create a few web pages that extract data from the database and displays it as HTML. In fact if there is an existing page template that you can use for the header and footer, you can develop the entire Faculty website in under an hour (you just have to create 3 pages).

'''Question''': How will the Program Assistants update the information in the database?

'''Answer''': OK, let's assume that you're not going to teach them SQL and that a DB Admin tool will also be too difficult to learn. Then you have to create HTML forms to update records in the database.

Ouch! What was easy just became hard. Making HTML forms is a real pain, because you have to validate the input, deal with file uploads, and also make sure that everything is stored to the database OK without losing any information. Such a basic task, but it can be very difficult. This is when it is time to use Xataface.

====Solution 5: Use Xataface====

OK, this isn't really its own solution. It is more like ""Solution 4 Part II"", because Xataface is intended to complement your custom application you built with solution 4, by providing an easy-to-use, configurable user interface that is targeted at secretaries and normal users (as opposed to database administrators). A Xataface application takes only seconds to set up and it will provide you with a full user interface for your users to edit information in the database.","introduction motivation why",en,
GettingStarted:Installation,73,Installation,"==Installation==

Download and installation instructions for the Web Lite framework.
Xataface is a 100% PHP Framework that comes with all dependencies as part of the installation. The framework itself lives inside a single directory that should be placed inside the document root of your web server so that it can be accessed from the web. You can install a single copy of Xataface to be used by multiple applications on your web server. Each application just ""requires"" the key files from the Web Lite framework.

===Downloading===

# Go to the Xataface Sourceforge project file releases page
# Download the latest file release.

===Installing===

# Unpack the gzipped tar archive that you downloaded somewhere in your web server's document root (i.e., make sure that the 'dataface' directory is in a web-accessible location).
# Make the dataface/Dataface/templates_c directory writable by the web server.  An unsafe way to do this is to 
 chmod 777 Dataface/templates_c
But it would be better to just give write access to the web server user.
# Confirm that the installation worked by pointing the web browser to http://yourdomain.com/path/to/dataface/dataface_info.php . If it worked OK, you should receive a web page that says ""Dataface is installed correctly"", along with some basic instructions for creating a Xataface Application. (Note: Sometimes this page will give you a false positive. i.e., it may say the installation worked but then your Xataface application receives errors. Check the troubleshooting section below to deal with these issues).

===Troubleshooting===

If your installation is not going as planned, don't panic. There is a possiblity that your system has a slightly different configuration and you have to make some small adjustments to make the installation work.

The general procedure for troubleshooting the installation is as follows:

# Check the [[Troubleshooting]] page.
# Look through the [http://xataface.com/forum forum] to see if others have experienced the same thing.
# Post your question in the forum if you can't find the answer already.

","installation troubleshooting downloading ",en,
GettingStarted:first_application,74,"Creating your First Application","==Creating Your First Application==

Build a simple Xataface application.

For our first Xataface application we will try to build a web site for Faculty of Widgetry (From the example in the ""Why Use Xataface"" page). The web site needs to store information about programs and courses. An entity-relationship diagram (ERD) for this website is included below:

[[Image:http://xataface.com/documentation/tutorial/getting_started/er-diagram.png]]

As the ERD shows, our database will need 2 tables (Course and Program). Our next step is to build this database. You can use any MySQL database administration tool to builld the database. My personal tool of choice is PHPMyAdmin.

===Step 1: Creating the database using PHPMyAdmin===

The following steps describe the procedure for creating this database using PHPMyAdmin.

# At the main menu of PHPMyAdmin, type 'FacultyOfWidgetry' into the 'Create new database field' as follows: <nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/new_database.gif]] <nowiki><br/></nowiki>Then click 'Create'.
# First we will create the 'Course' table to hold course information. In the 'FacultyOfWidgetry' page, fill in the 'Create new table text field as follows: <nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/create_table.gif]] <nowiki><br/></nowiki> Then click 'Go'.
# This should bring up a form to specify the fields for the course table: <nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/course-table-def-small.gif]] <nowiki><br/></nowiki> Then click ""Save"". The resulting SQL to create the Course table is as follows:<code>
CREATE TABLE `Course` (
 `CourseID` int(11) NOT NULL auto_increment,
 `ProgramID` int(11),
 `CourseTitle` varchar(64) NOT NULL default '',
 `CourseDescription` text NOT NULL,
 `HTMLOutline` text NOT NULL,
 `PDFOutline` longblob NOT NULL,
 `PDFOutline_mimetype` varchar(64),
 `Subject` varchar(128) NOT NULL default '',
 `CourseNumber` varchar(10) NOT NULL default '',
 `Credits` int(5) NOT NULL default '0',
 `LastModified` timestamp NOT NULL default CURRENT_TIMESTAMP,
 PRIMARY KEY (`CourseID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Store courses' AUTO_INCREMENT=1 ;
</code>
#In a similar fashion, create the Program table. The resulting SQL for this table is:<code>
CREATE TABLE `Program` (
 `ProgramID` int(11) NOT NULL auto_increment,
 `ProgramName` varchar(64) NOT NULL default '',
 `ProgramDescription` text NOT NULL,
 `HTMLOutline` text NOT NULL,
 `PDFOutline` longblob NOT NULL,
 `PDFOutline_mimetype` varchar(32),
 `AdmissionDeadline` date NOT NULL default '0000-00-00',
 `LastModified` timestamp NOT NULL default CURRENT_TIMESTAMP,
 PRIMARY KEY (`ProgramID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Academic Program' AUTO_INCREMENT=1 ;
</code>
# The database has been created with 2 tables: Program and Course. We can now move on to building the Xataface application.

===Step 2: Create Xataface Application===

Our Xataface application will provide a user-friendly front-end to our database. A basic application consists of a directory with a configuration file and an entry page (PHP file). Xataface comes with a PHP setup script (called makesite) to create the skeleton for your application. Alternatively you can set up the application manually.

Note: For the following instructions and examples, my Daface installation is located at /Users/shannah/Sites/dataface and the URL for the installation is http://localhost/~shannah/dataface.

====Method 1: Setting up application with the 'makesite' script====

# From the command prompt, navigate to the dataface directory. (in my case ''/Users/shannah/Sites/dataface'').
# This directory contains a file named 'makesite'. It is a PHP script that can be used to build a website powered by Xataface. To find out the usage options for this script you can simply call the script with no parameters. E.g.,<code> 
stevepbook:~/Sites/dataface shannah$ ./makesite
</code>
# This will give you usage instructions for the script as follows:<code>
makesite: invalid options entered.

 Usage: makesite <site_path> <db_user>:<db_pass>@<db_host>/<db_name> <dataface_url>
 or
 php makesite <site_path> <db_user>:<db_pass>@<db_host>/<db_name> <dataface_url>
 where 
 <site_path> = The path (absolute or relative) to your application directory.
 <db_user> = The MySQL username to connect to the database
 <db_pass> = The User's password to connect to the database
 <db_host> = The MySQL host name.
 <db_name> = The name of the mysql database for the application.
 <dataface_url> = The URL to the Xataface installation

 Examples:

 makesite ../FacultyOfWidgetry root:password@localhost/FacultyOfWidgetry /dataface

 The above command would create a site at ../FacultyOfWidgetry (i.e., the Faculty of 
 Widgetry directory in the parent directory. The database used for this site is 
 located at localhost, and the database name is FacultyOfWidgetry. The username
 to connect to the database is root and his password is password.
</code>
# We create our FacultyOfWidgetry site using the following command:<code>
./makesite ../FacultyOfWidgetry \
    root@localhost/FacultyOfWidgetry \
    http://localhost/~shannah/dataface
</code>
# This will create our application in the FacultyOfWidgetry folder if everything worked ok. The contents of the folder will look like: <nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/directory-structure-1.gif]]

You may be wondering what these files. Here is the short version (Read the next section ""Creating applications manually"" for more detailed information about the contents of these files.

The index.php file is the entry point for your application (i.e., you point the web browser at this file to use the application. 
The conf.ini file contains database connection settings and some other minor settings, like what should appear in the navigation menu.
The tables/Program (tables/Course) directory can contain configuration files specific to the Program (Course) table. More on that later. 

# Point your web browser to the FacultyOfWidgetry directory to see the application: <nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/basic-application-1.gif]]
#Your application is now created. It will enable you to add, edit, delete, and find records in either the Course table or the Program table. There will be more on the basics of using this application in the next section.	

====Method 2: Setting up application manually====

Using the makesite script as described above is the recommended way to set up an application because it saves time. However, it is very easy to set up the application manually. Just follow these steps:

# Create a directory for the application somewhere in your web site (preferably outside your xataface directory). We will call our directory 'FacultyOfWidgetry'. ):<code>
mkdir FacultyOfWidgetry
</code>
# Create a PHP file to serve as the access point for the application. Generally we will name this file 'index.php', but you can name it anything. Place the following contents in the index.php file:<code>
<?
require_once '/path/to/dataface/dataface-public-api.php';
df_init(__FILE__, 'http://yourdomain.com/dataface');
$app =& Dataface_Application::getInstance();
$app->display();
</code><nowiki><p>OK, I guess some explanations are in order.</p><p>
The first line imports the all of the public functions for dataface from the dataface-public-api.php file.</p><p>
The second line initializes the application for the current directory and specifies the URL to the dataface installation.</p><p>
The third line obtains an instance to the Application object - the core of your Dataface application.</p><p>
The fourth line simply displays the application.</p></nowiki>
# Create a file named 'conf.ini' to contain database connection information. Its contents should be:<code>
[_database]
	host = ""localhost""
	user = ""dbuser""
	password = ""secret""
	name = ""FacultyOfWidgetry""

[_tables]
	Course = ""Course""
	Program = ""Program""
</code><nowiki><p><b>Explanations:</b></p><p>There are 2 sections in this INI file: '_database', and '_tables'.</p><p>
The '_database' section specifies the database connection information for the MySQL database.</p><p>
The '_tables' section specifies which tables will be included in the navigation menu for the application.</p></nowiki>
# At this point, the application is functional. However there is one more thing that should be done for security reasons. The conf.ini file contains sensitive password information and should not be served to the web. We will create an .htaccess file to tell Apache NOT to serve this (or any) .ini file. The .htaccess file should contain:<code>
<FilesMatch ""\.ini$"">
	Deny from all
</FilesMatch></code>
# The directory structure of your application will now look like: <nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/basic-app-dir-structure-manual-1.gif]]<nowiki><p>
Note, however, that there is also an .htaccess file that is hidden from this image.</p><p>You may be wondering why there is no 'tables' directory like the directory structure that was generated by the makesite script. The 'tables' directory is not required for the application to be functional. It will be required later on when we start to decorate the database.</p></nowiki>
# The application is now ready to go. Point your web browser to the index.php file that you created. It will look like:<nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/basic-application-1.gif]]

===Download source files===

[[File:http://xataface.com/documentation/tutorial/getting_started/facultyofwidgetry-4-tar.gz|Download the source files]] for this application at a tar.gz archive.
These files reflect the state of the application at this point of the tutorial. As later sections make changes to the application you will be able to download those versions also.","htaccess first application installation",en,
GettingStarted:using_first_app,75,"Using Your First Application","==Using Your First Application==

A Web Lite application, at its core, provides 4 standard operations: Add new records, edit existing records, delete records, and find records. This section gives a brief overview of how to use your first Dataface application.
When you first create your Xataface application and there are no records in the database, the application will look quite plain. If you point your web browser to your newly created application it will look something like:

[[Image:http://xataface.com/documentation/tutorial/getting_started/basic-application-1.gif]]

You may be wondering why it says ""No records matched your request"" when you haven't even really made a request. This is because the 'default' request that is performed if no other request is specified is to show the first record from the first table in the navigation menu. Since there are no records, it is true that there are NO records matching the default request.
So what can you do with this application anyways? Essentially there are 4 operations you will want to perform:

# Create new records
# Edit Existing records
# Find records
# Delete records

==Basic Navigation==

The navigation tabs (aka Navigation menu) at the top left represent the tables in your database. You can navigate to any of the tables in this list by clicking on that table:

[[Image:http://xataface.com/documentation/tutorial/getting_started/navmenu-1.gif]]

There are 3 ""views"" associated with tables in the database:

* '''Details''' - Shows the details of a single record in the table
* '''List''' - Shows the records in the current ""found set"" as a list. (in a table).
* '''Find''' - Allows users to find records matching certain criteria.

You can toggle between these 3 views using the tabs at the top of the page:

[[Image:http://xataface.com/documentation/tutorial/getting_started/basic-tabs-1.gif]]

===The ""Found Set""===

Throughout this tutorial you will see the phrase ""found set"" an awful lot, so it is important to understand just what this means. A ""found set"" is the set of all records in the current table that match the current ""find criteria"". This begs the question, ""what is 'find criteria'?"". By default there is no find criteria. When you perform a search or a find on the current table, you add ""find criteria"" so that only the records satisfying these criteria will be included in the ""found set"".

For example, if you click on the ""find"" tab, you will get a search form that allows you to search for records that match certain criteria. The ""find"" tab for the ""Course"" table in our application looks like:

[[Image:http://xataface.com/documentation/tutorial/getting_started/find-form-1.gif]]

If you type in ""English"" in the ""Subject"" field and click ""Find"", then the ""found set"" will consist of only records that contain the word ""English"" in their subject fields.

On the top left of the application window there will always be a ""Found"" line that indicates how many records are currently in the found set. e.g., 

This indicates that there are 256 records in the current table (which is the 'Groups' table). There are currently only 225 records in the current ""found set"" (meaning that we have performed a ""find"" operation and it matched 225 of the records). It also indicates that the currently displayed record is record number 1 out of the 225 found records.

===The Actions Menu===

Just below the view tabs ('details', 'list', and 'find') there are a few buttons that allow you to perform actions such as create new records, clear find parameters (i.e. Show All), and delete records.

[[Image:http://xataface.com/documentation/tutorial/getting_started/actions-menu-1.gif]]

'''Descriptions:'''

* '''new record''' - Creates a new record in the current table.
* '''show all''' - Clears all find criteria on current table so that all records are shown.
* '''delete''' - Deletes the current record in the table.
* '''delete found records''' - Deletes all records in the current ""found set"". If no find criteria is specified this will delete all records in the table. 

===Creating new records===

The basic FacultyOfWidgetry application that we created in the previous section isn't very interesting when it doesn't contain any records, so let's create some Program records.

# Select the ""Program"" table by clicking on the ""Program"" option of the navigation menu.
# Click ""new record"" in the actions menu (top left).
# This will bring up a form to insert a new record that looks like: <nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/new-record-1.gif]]
# Fill in the form and click ""Save"". If everything went OK, you will see the same form again, but with a ""success"" message at the top of the page: <nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/successfully-saved-1.gif]]

===Editing an existing record===

The ""details"" view allows you to view details or edit the current record. There should be at least 2 sub-tabs: 'View' and 'Edit'. If you click on the 'Edit' tab, you will be presented with a form to edit the record. The form is identical to the ""create new record"" form.

===Deleting records===

If the 'list' tab is selected, then you will see a button called 'delete found records' in the actions menu (just below the view tabs). Alternatively if the 'details' tab is selected, you will see a button called simply 'delete'. 

[[Image:http://xataface.com/documentation/tutorial/getting_started/actions-menu-1.gif]]

Select ""delete"" to delete only the current record you are viewing in the ""details"" view.

Select ""delete found records"" to delete all of the records in the current found set. 

In either case, you will be prompted to confirm your decision before the records are actually deleted.

===Interface Overview===

Xataface applications provide an intuitive and consistent interface throughout. The following screenshot contains a map of some comment interface components along with some explanations:

[[Image:http://xataface.com/documentation/tutorial/getting_started/interface-schematic.png]]


Other topics
This short section is only intended to get you acquainted with the basics of Xataface applications. As your application becomes more complex with relationships and value-lists, there will be other usage scenarios of interest.","""find form"",""edit form"",""delete record"",""user interface"",ui,template,look and feel",en,
GettingStarted:customizing,76,"Customizing Field labels, descriptions, and widgets","==Customizing Field labels, descriptions, and widgets==

Using simple INI configuration files, you can customize the look and feel of your application. You can change widgets, labels, field descriptions, and more.
In the previous 2 sections we learned how to create a simple application by desiging a database and then installing the basic directory structure to make our application operational. Now it is time to ""decorate"" the application a little bit. Decoration occurs by way of simple configuration files that are placed in strategic locations in the application. We can customize such things as:

* Widget types (e.g., use a select list for a field rather than a text field)
* Labels (e.g., The ProgramName field's label can say ""Program Name"" instead of just ""ProgramName"")
* Field Descriptions . You can add descriptions to fields to help explain their meaning and how to use the application.
* HTML attributes. (e.g., Make a text field 50 characters wide)

===Table Configuration Directories===

You will recall, that when we used the 'makesite' script to generate the directory structure for our web application, it created a directory named 'tables', with subdirectories named after each of the tables in our database. The directory structure of the application looked like:

[[Image:http://xataface.com/documentation/tutorial/getting_started/directory-structure-1.gif]]

The 'tables/Program' and 'tables/Course' are refered to as ""table configuration directories"" . All of the configuration files a table in a Xataface application are stored in its associated table configuration directory. For example all configuration files for the 'Program' table are located in the 'tables/Program' directory.

There are 4 main files that are generally contained in a table's configuration directory:

* '''fields.ini''' - Contains configuration for the fields of the table (e.g., field labels, descriptions, widget types, etc...)
* ''valuelists.ini''' - Contains value lists (vocabularies) that can be used in the table to limit input into certain fields like select lists.
* '''relationships.ini''' - Defines the relationships between this table and other tables in the application.
* '''<TableName>.php''' (where <TableName> is the name of the table. - A delegate PHP class that allows you to further customize the behavior of the application with respect to this table. May contain custom fields, importing/exporting functionality, permissions information, and more...

===Customizing Labels and Descriptions===

We will start off by adding custom labels and descriptions to the 'Program' table of our 'FacultyOfWidgetry' application. This sort of customization settings are placed in a file named 'fields.ini' inside the table's configuration directory.

# Create the 'fields.ini' file in the Program table configuration directory (i.e., tables/Programs/fields.ini).
# Add the following to this file:<code>
[ProgramName]
	widget:label = ""Program Name""
	widget:description = ""Enter the name of the program""
</code><nowiki><br></nowiki>Now look at the ""Edit Record"" form in the Xataface application:

[[Image:http://xataface.com/documentation/tutorial/getting_started/program-name-label-1.gif]]


Notice how the label for the ""ProgramName"" now says ""Program Name"" (note the space between ""Program"" and ""Name""). And its description matches the description specified in the fields.ini file.

The widget:label and widget:description attributes can be defined for any field in any table of the application.

===Using different widgets===

If no widgets are defined in the fields.ini file, a Xataface application will make a best guess at the type of widget that should be used to edit the value in a field. In general, the widgets used by default are as follows:

* VARCHAR, CHAR, INT : html text field
* DATE, DATETIME fields: calendar widget
* TEXT fields : html text area
* BLOB fields : html file upload field
* INT Fields with ""AUTO INCREMENT"" : html hidden field
* VARCHAR or CHAR fields with ""Password"" or ""password"" as part of the name : html password field
* ENUM fields : html select list
* SET fields : html checkbox group (not yet supported as of this writing).

You can change the widget that is used to edit a field by specifying a ""widget:type"" attribute for the field in the fields.ini file. For more information about the available widgets, see [[widget:type]].

====Example: Using HTML Editor to edit the HTMLOutline field====

Clearly the HTMLOutline field in the Program table is intended to store HTML content. By default our application only provides a text area to do the editing so the user is expected to enter the HTML markup by hand. It would be much better to provide the user with a WYSIWYG (What you see is what you get) HTML editor widget. That is exactly what we are going to do.
We will add a section to the fields.ini file so that it now looks like: <code>
[ProgramName]
	widget:label = ""Program Name""
	widget:description = ""Enter the name of the program""

[HTMLOutline]
	widget:type = ""htmlarea""
</code>

Now refresh the Xataface application in your web browser and look at the edit form for a record of the Program table:

[[Image:http://xataface.com/documentation/tutorial/getting_started/htmlarea-1.gif]]

As you can see, the HTMLOutline field now has an HTML Editor widget for editing. Most users will find this much nicer to work with than a normal text area. Xataface uses FCKEditor for its html editor widget.

There are a number of widgets that can be specified in the [[widget:type]] parameter:

* '''[[checkbox]]''' - An HTML checkbox (or checkbox group depending on context).
* '''[[date]]''' - Month/Day/Year select lists for selecting dates.
* '''[[calendar]]''' - A text field with a button that opens a small calendar widget when clicked.
* '''[[group]]''' - A complex widget type for editing multiple values as a group (useful for XML fields)
* '''[[hidden]]''' - a hidden field
* '''[[password]]''' - An HTML password widget
* '''[[select]]''' - An HTML select list (requires the 'vocabulary' attribute)
* '''[[static]]''' - an uneditable field
* '''[[table]]''' - A complex widget type for editing multiple values in a tabular format (Useful for XML fields)
* '''[[text]]''' - an html text field
* '''[[textarea]]''' - an html text area

===Changing HTML attributes of widgets===

Sometimes you may want even finer grained control of your widgets' appearance than to just specify the type, label, and desription. Perhaps you want to make a text field 50 characters wide, or to set the CSS class of the html element. This can be done using the 'widget:atts:' parameter for a field. A short example is the easiest way to explain how this works.

Modify the fields.ini for the Program table so it looks like:<code>
[ProgramName]
widget:label = ""Program Name""
widget:description = ""Enter the name of the program""
widget:atts:size = 50
widget:atts:style = ""font-size: 24pt; font-family: Apple Chancery""

[HTMLOutline]
widget:type = htmlarea
</code>

We have added 2 lines:<code>
widget:atts:size = 50
widget:atts:style = ""font-size: 24pt; font-family: Apple Chancery""
</code>

What this does is add the html attributes size=""50"" and style=""font-size: 24pt; font-family: Apple Chancery"" to the html text field that is used to edit the ProgramName field.
Look at the results:

[[Image:http://xataface.com/documentation/tutorial/getting_started/widget-atts-1.gif]]

The HTML tag for the text field now looks like:<code>
<input class=""default"" id=""ProgramName"" name=""ProgramName"" 
	type=""text"" size=""50"" 
	style=""font-size: 24pt; 
		font-family: Apple Chancery"" 
	value=""Basic Widgetry"" 
/>	
</code>
In fact you can add arbitrary attributes to any of the fields using the same convention. Some useful examples are:

* '''[[widget:atts:rows]]''' for text areas to set the number of rows of text they should display.
* '''[[widget:atts:cols]]''' for text areas to set the number of columns (1 character = 1 column)
You can even use javascript calls in here if you like:
* '''[[widget:atts:onclick]]''' = ""doJsFunction();""

===Download source files===

[http://xataface.com/documentation/tutorial/getting_started/facultyofwidgetry-6-tar.gz Download the source files] for this application as a tar.gz archive
These source files reflect the state of the application at the current point of the tutorial. As changes are made to the application in later sections, downloads of those versions are made available for download also.

===Summary===
In this section we learned how to change the labels, descriptions, and widgets for fields. We also learned how to add HTML attributes to the widgets to achieve very fine-grained control over the display of our forms.","widget labels descriptions onclick handlers",en,
GettingStarted:valuelists,77,"Using Valuelists","==Using Value-lists==

Value-lists serve as vocabularies that can be used for fields such as select lists, checkbox groups, and auto-complete fields.

So far we have not used any enumerated fields such as select lists, checkbox groups, or auto-completion fields in our examples. This is because we are missing a key ingredient that is required by all of these widget types: a vocabulary. We need a way to define options for these fields.

This is where 'valuelists' come into play. A valuelists is essentially a list of key-value pairs that can be used as a vocabulary in enumerated fields like checkbox groups, select lists, and auto-completion fields. Valuelists are defined in the valuelists.ini file in each table's configuration directory.

===Example 1: Use a select list for the Subject field in the Course table===

The ""Subject"" field in the ""Course"" table really shouldn't be a free-form field that will accept any value. The user should just be able to pick from a finite list of subjects in a select list. To make these changes we will follow these steps:

# Create the configuration directory for the ""Course"" table if it does not exist yet.
# Create a file named 'fields.ini' inside the Course table's configuration directory (i.e., tables/Course/fields.ini), if it does not already exist.
# Create a file named 'valuelists.ini' inside the Course table's configuration directory (i.e., tables/Course/valuelists.ini) if it does not already exist.
Your application directory structure should now look like:<nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/application-structure-valuelists.gif]]
# Edit the valuelists.ini file so that it looks like:<code>
[Subjects]
	ENGL = English
	MATH = Math
	PHYS = Physics
	CHEM = Chemistry
</code> This defines a valuelist named 'Subjects' with values {ENGL, MATH, PHYS, CHEM} and associated labels {English, Math, Physics, Chemistry}. The values (i.e., ENGL, MATH, etc..) represent what will be stored in the database, and the values is a user-friendly representation that will be displayed on the screen.
# Now we edit the fields.ini file so that it looks like:<code>
[Subject]
	widget:type = select
	vocabulary = Subjects
</code> This tells Xataface that we want to use a select widget to edit the ""Subject"" field, and its values should be drawn from the ""Subjects"" valuelist.
#Navigate to the ""Course"" table in our application and select ""new record"" from the ""Actions to be performed menu"" in the top left.<nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/actions-menu-1.gif]]<nowiki><br/><br/></nowiki>This will bring up a form to create a new Course record, so that we can see what the form looks like. It should look like:<nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/new-course-form-1.gif]]<nowiki><br/></nowiki>Notice that the ""Subject"" field is represented by a select widget, its options are as follows:<nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/course-subject-pulldown-1.gif]]<nowiki><br/></nowiki> And if you look at the HTML source code for this select list, it would look like:<code>
<select class=""default"" id=""Subject"" name=""Subject"">
	<option value="""">Please Select...</option>
	<option value=""ENGL"">English</option>
	<option value=""MATH"">Math</option>
	<option value=""PHYS"">Physics</option>
	<option value=""CHEM"">Chemistry</option>
</select>
</code>

===Example 2: Using a checkbox group for the 'Subject' field===

In Example 1, we showed how to use a select list for the 'Subject' field in the 'Course' table. This is great if each course can only be one subject. But what if a course can be categorized in 2 subject areas. Then we will need a widget the allows you to select multiple items. Checkbox groups work well for this.
Make a change to the 'fields.ini' file for the 'Course' table to change the widget:type attribute of the 'Subject' field to 'checkbox' as follows:<code>
[Subject]
widget:type = checkbox
vocabulary = Subjects
</code>

Now load the form again and notice that the 'Subject' field is now represented by checkboxes.

[[Image:http://xataface.com/documentation/tutorial/getting_started/checkbox-group-1.gif]]

You may be wondering how we store multiple values in a single field. In this case Subject is treated as a 'repeat' field where each value is on a separate line. I.e., with the form above, if we clicked 'save' and checked the values stored in the database we would see:<code>
PHYS
CHEM
</code>

As the value in the 'Subject' field. Please note that if you are going to use a repeating field like this, you should make sure that the field is 'big' enough to store all of the values. E.g., I think my Subject field was a VARCHAR(64) (64 characters long), so the sum of the lengths of all of the values 'checked' for 'Subject' should be less than 64.

===Example 3: Dynamic Valuelists based on the results of SQL queries===

Example 1 & 2 demonstrated the basic idea of valuelists and how they can be used as values for select lists and checkbox groups. However defining valuelists ""statically"" inside the valuelists.ini file doesn't really seem to offer anything over using and ENUM or SET field in the MySQL database. In many cases we want the user to be able to choose from a number of options that are pulled from the database. For example, we may want the user to be able to specify the Program that a Course belongs to, using a pull-down list.

Recall that when we created the 'Course' table we included a field named 'ProgramID' to store the ID number of the Program that this course belongs to. It would be unreasonable to expect the users of your application to remember the ID number of the Program to which the course belongs when they are filling in the 'Course' form. It would be much better if the user could choose the program from a list of available programs. Fortunately, this functionality is simple to add:

# Add a valuelist named 'Programs' to the valuelists.ini file for the 'Course' table as follows:<code>
[Programs]
	__sql__ = ""SELECT ProgramID, ProgramName FROM Program ORDER BY ProgramName""
</code> '''Note: Make sure you use two underscores on either side of 'sql' in the above example. It should be '__sql__' not '_sql_'.'''<nowiki><p></nowiki>This valuelist will be a list of the records in the 'Program' table in alphabetical order on the program name. Note that this query selects 2 columns. The first column is always taken to be the ID column of the value-list and the 2nd column (if specified) is the Name column of the valuelist. The ID column is what will actually be stored in the database, and the Name column is what will be shown to the user in place of the ID.<nowiki></p></nowiki>
# Add a field definition for the ProgramID field in the fields.ini file of the 'Course' table as follows:<code>
[ProgramID]
	widget:type = select
	vocabulary = Programs
</code>

Now we can load up our form and see what it looks like:

[[Image:http://xataface.com/documentation/tutorial/getting_started/programid-select-list.gif]]

We can see that the ProgramID field now appears with a select list of all of the programs in the database. The HTML code for the select list is:<code>
<select class=""default"" id=""ProgramID"" name=""ProgramID"">
	<option value="""">Please Select...</option>
	<option value=""2"">Advanced Widgetry</option>
	<option value=""1"">Basic Widgetry</option>
	<option value=""3"">International Widgetry</option>
</select></code>

===Download Source Files===

[http://xataface.com/documentation/tutorial/getting_started/facultyofwidgetry-7-tar.gz Download application source files as tar.gz archive]

These source files reflect the application's state at this point in the tutorial. As changes are made to the application in later sections, modified source archives will be available to be downloaded.

===Summary===

In this section, we have learned how to use valuelists to add selection lists and checkbox groups to our web forms. We also shows how valuelists can be dynamically defined using SQL. Using valuelists in this way is like defining a many-to-one relationship to our database (in example 3, it was many 'Course' records to one 'Program' record). In the next section we will learn how to add many-to-many and one-to-many relationships to our database in such a way that records can be easily added and removed from relationships using Xataface.","valuelists, __sql__, select lists, checkbox options,checkbox groups,vocabularies",en,
GettingStarted:relationships,78,Relationships,"==Relationships==

Xataface allows you to define relationships between tables using the relationships.ini file.

Xataface applications without relationships between tables can be quite boring. In our FacultyOfWidgetry application, we have implicitly defined a relationship between the Program table and the Course table by adding a ProgramID field to the Course table. In the previous section we saw how to configure this relationship from the context of a 'Course' by adding a select list to the Course table form to select the Program that the Course belongs to.

From the 'Program' side it is a little bit more complicated. There are no fields in the 'Program' table that can be edited to add a 'Course' to the list of courses in a 'Program', and it would be highly inconvenient to have to edit a 'Course' record in order to add the course to a 'Program'. What we want is a sort of 'Add Course' button to add a course to a 'Program'. 

===Concepts, Definitions, and Terminology===

Before we can delve into examples, it will help to go over some of the concepts and terminology involved in relationships using Xataface. Xataface relationships are always defined in a one-way fashion from the point of view of one table. For example, if you define a one-to-many relationship from the 'Program' table to the 'Course' table, the mirror (many-to-one) relationship from 'Course' to 'Program' is not automatically created. This method of defining relationships allows us to unambiguously refer to the source and destination tables of a relationship.

'''Definition 1:''' The ''source table'' of a relationship is the table on which a relationship is defined. For example if we define a relationship named 'Courses' on the 'Program' table to associate courses in a given program, then the 'Program' table would be considered the source table of the relationship, and the 'Course' table would be a destination table of the relationship.

'''Definition 2:''' The ''destination table'' of a relationship a table from which related records are selected.

There may be multiple destination tables in a given relationship but only one source table. If there are multiple destination tables, then one of these tables is designated as the domain table and the remaining destination tables are called join tables. 

'''Definition 3:''' A ''domain table'' is a destination table which stores the object of the relationship. For example if we define a many-to-many relationship between the 'Program' table and the 'Course' table, (i.e., each program can contain multiple courses and each course can be part of multiple programs), then we would need to add a join table to map 'Course' records to 'Program' records. Let's call this table 'ProgramCourses'. Each record of the 'ProgramCourses' table would contain a 2 fields: a 'ProgramID' field (to reference the program) and a 'CourseID' field to reference the course. If we define the relationship from the point of view of a 'Program' then the 'Program' table would be the source table, the 'ProgramCourses' table would be the join table, and the 'Course' table would be the domain table.

Don't worry if these definitions and terms aren't clear at this point. Use this section as a reference for when you run across the terms later in the tutorial.

===Defining a relationship===

To define a relationship in Xataface, all you need to do is tell Xataface how to select the related records using SQL. Xataface will be able to figure out how to add/remove records to the relationship from this information. This information is defined inside a the 'relationships.ini' file inside the configuration folder for the table.

====Example 1: Adding a 'Courses' relationship to the 'Program' table====

We want to be able to associate multiple courses with each program. We do this by defining a relationship on the 'Program' table as follows:

# Add a file named 'relationships.ini' to the 'Program' table's configuration folder (i.e., tables/Program/relationships.ini). Your application's directory structure should now look like:<nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/directory-structure-relationships.gif]]<nowiki><br/></nowiki>Notice, in particular the addition of the 'relationships.ini' file in the 'Program' directory.
# Add the following to the 'relationships.ini' file:<code>
[Courses]
	Course.ProgramID = ""$ProgramID""
</code>	

This little snippet defines a relationship named 'Courses' on the 'Program' table. 'Program' is the source table. 'Course' is the destination table. There are no join tables because this is only a one-to-many relationship. You may be wondering what the $ProgramID means. This is a variable that represents the value of the 'ProgramID' field in the source record. This relationship specifies that courses whose 'ProgramID' field matches the value of the 'ProgramID' field in the source record, are related to the source record. The english language makes this seem more difficult and complex than it really is.

Let's check out our changes. Since we have defined the relationship on the 'Program' table, we will click on the 'Program' link in the navigation menu:
[[Image:http://xataface.com/documentation/tutorial/getting_started/course-relationship-defined-1.gif]]

Notice that there is now a 'course' tab at the top of the page. Click on this tab to see the courses that are related to this Program (as defined by our 'Courses' relationship). If it says that ""No records matched the request"" or something to that effect, then you don't have any Course records in the relationship yet. Just click the ""Add New Courses Record"" button in the upper left to add a course. If there are courses in the relationship, then the Courses tab will look something like:

[[Image:http://xataface.com/documentation/tutorial/getting_started/courses-related-records.gif]]

Currently there is only one course in the program, but we can add more. If you click on the ""Add New Courses"" button in the upper left, you will be presented with a new course form that will allow you to add a new course in this Program.

===Example 2: Making the 'Courses' relationship a Many-to-Many relationship===

Example 1 shows how Xataface can handle a one-to-many relationship. Now we will alter the database a little bit and turn this into a many-to-many relationship.

# Add a table named 'ProgramCourses' to the database. The SQL table definition for this table should be something like:<code>
CREATE  TABLE  `ProgramCourses` (
	`ProgramID` INT( 11  )  NOT  NULL ,
	`CourseID` INT( 11  )  NOT  NULL ,
	PRIMARY  KEY (  `ProgramID` ,  `CourseID`  ) 
	) 
</code><nowiki><p>Note that it is important for ALL of your tables to have Primary keys. If a table is missing its primary keys, some strange behavior may occur with relationships involving that table.</p>
<p>
The above defined table will serve as a join table between 'Program' and 'Course'
</p></nowiki>
# Since this is now going to be a many-to-many relationship, we no longer need the 'ProgramID' field in the 'Course' table. (Do not confuse this with the ProgramID field in the 'Program' table. That field is important and needed.). Before removing this field, we will transfer the information across so that the existing relationships are maintained. The following SQL query will effectively all of the old one-to-many relationships into equivalent many-to-many relationships:<code>
INSERT  INTO ProgramCourses( ProgramID, CourseID ) 
	SELECT ProgramID, CourseID
	FROM Course
</code><nowiki><p>	
And now we can remove the 'ProgramID' field from the 'Course' table.
ALTER  TABLE  Course  DROP  ProgramID</p></nowiki>
# Finally, we will need to modify the relationship definition in the relationships.ini file of the 'Program' table:<code>
[Courses]
	Course.CourseID = ProgramCourses.CourseID
	ProgramCourses.ProgramID = ""$ProgramID"" 
</code><nowiki><p>
This means that all courses for which a (ProgramID, CourseID) pair matches the CourseID of the course and the ProgramID of the source Program record are included in the relationship.</p></nowiki>
# Now we can check our application for changes. Go to the 'Program' table in your application (using your web browser) and click on the 'courses' tab once again:<nowiki><br/></nowiki>[[Image:http://xataface.com/documentation/tutorial/getting_started/multi-relationship.gif]]<nowiki>
<p>
This looks almost the same as before. Notice, however that now there is an ""Add Existing Courses Record"" button at the top. This is because with a many-to-many relationship, you are able to add related records in 2 ways:</p></nowiki>
## Adding a completely new record that did not exist before.
## Selecting a record that already exists and adding it to the relationship.

===Example 3: Defining Relationships using SQL===

The previous examples used a simple INI file syntax to define relationships. However, some people may be more comfortable defining their relationships using SQL. This is also possible. Let's look at the relationships.ini file from example 1:<code>
[Courses]
	Course.ProgramID = ""$ProgramID""
</code>

This also could have been defined as follows:<code>
[Courses]
	__sql__ = ""SELECT * FROM Course WHERE ProgramID='$ProgramID'""
</code>

'''Note: Make sure you use two underscores on either side of 'sql' in the above example. It should be '__sql__' not '_sql_'.'''

The two syntaxes are equivalent. In fact, the former will be converted into the later by Xataface behind the scenes.

Now let's look at example 2's relationships.ini file:<code>
[Courses]
	Course.CourseID = ProgramCourses.CourseID
	ProgramCourses.ProgramID = ""$ProgramID"" 
</code>

This could have been written as:<code>
[Courses]
	__sql__ = ""SELECT * 
		FROM ProgramCourses, Course 
		WHERE Course.CourseID = ProgramCourses.CourseID 
		AND ProgramCourses.ProgramID = '$ProgramID'""
</code>

The two are equivalent. This example, however, shows how defining a relationship using SQL can be beneficial. The above SQL query will work but it can be done better using Joins as follows:<code>
[Courses]
	__sql__ = ""SELECT * 
		FROM ProgramCourses pc 
		INNER JOIN Course c ON pc.CourseID = c.CourseID 
		WHERE pc.ProgramID = '$ProgramID'""
</code>

All of these 3 methods will produce the same results, but the last one will probably give a little bit better performance.

===Relationship Restrictions===

Xataface has built-in logic to figure out how to add new and existing records to relationships that you define, as long as your relationships obey a few guidelines.

# All tables must have a Primary key
# The WHERE clause of your SQL definition for the relationship must contain only '=' comparisons, and 'AND' conjunctions. i.e., it cannot receive an 'OR' conjunction, nor can comparisons be done using '>', or '<'. This is because given 'AND' and '=' conjunctions it is easy for Xataface to be able to add records that will satisfy the relationship. If an 'OR' conjunction is used, it makes it ambiguous (though this will probably be corrected in future Xataface releases.

===Download Source Files===

[http://xataface.com/documentation/tutorial/getting_started/facultyofwidgetry-8-tar.gz Download the source files for this application as a tar.gz archive]",relationships,en,
GettingStarted:validation,79,"Form Validation","==Form Validation==

Xataface allows you to add validation rules to fields using the fields.ini file
A common requirement for forms is to have some validation rules. Here are some example validation rules:

* The Username field is required.
* The Username must be between 6 and 16 characters long.
* The password must have at least one letter and one digit.
* The Email field must contain a valid email address.

There is no end to the types of things that you will need to validate. Xataface takes care of most of this for you with both client-side (javascript) and server-side validation. All you have to do is define some validation rules in the fields.ini file.

===Example 1: Make 'Username' a required field===
<code>
[Username]
	validators:required = true
	validators:required:message = ""Username is required""
</code>

Placing the above inside the fields.ini file will cause the Username field to be a required field.

===Example 2: Username must be between 6 and 16 characters long===

For this rule we will use a regular expression.
<code>
[Username]
	validators:regex = ""/^.{6,16}$/""
	validators:regex:message = ""Username must be between 6 and 16 characters long""
</code>

===Example 3: Email field must contain a valid email address===

<code>
[Email]
	validators:email = true
	validators:regex:message = ""Email must contain a valid email address""
</code>

===Available validation rules===

Xataface uses the PEAR library HTML_Quickform for validation, so any of the validators available in this package will be available in Xataface. Some of the available validation rules include:

* required
* maxlength
* rangelength
* regex
* email
* emailorblank
* lettersonly
* alphanumeric
* numeric
* nopunctuation
* nonzero

===Default validation rules===

There are certain validation rules that are automatically applied to fields of with certain characteristics. For example, any field designated NOT NULL in the SQL table definition will automatically be a 'required' field. At the time of this writing, that is the only 'default' validation rule applied, but more may be added in the future if their addition makes sense.

","form validation,required field,validation rules",en,
GettingStarted:delegate_classes,80,"Delegate Classes","==Delegate Classes==

Use Delegate classes to add permissions, custom serialization, display filters, calculated fields, import/export functionality, and other custom functionality to your application.

For many applications, the configuration files provide sufficient to make them fit the requirements. However, in some cases you may feel the need to ""extend"" or ""bend"" your application even more. For these situations, there are delegate classes.

===What is a delegate class?===

A delegate class is a PHP class that defines custom behavior, functions, and fields for a table in a Xataface application. A table may have only 1 delegate class.

What kinds of things can a delegate class do?

* Define permission rules for tables, records, and relationships.
* Define calculated fields.
* Define custom serialization/deserialization of fields (useful for XML storage)
* Define custom event handlers (actions to be performed when certain events take place)
* Define import / export filters.
* Define custom titles for records
* more ...

===How to create a delegate class===

I will describe the creation process with an example. 

Referring back to our FacultyOfWidgetry application, let's add a delegate class for the 'Program' table. This is done as follows:

# Create a file named 'Program.php' in the Program table configuration directory (i.e., 'tables/Program/Program.php). Your application directory structure should now look like:<nowiki><br/></nowiki>[[Image:http://framework.weblite.ca/documentation/tutorial/getting_started/delegate-class-fs-1.gif]]
# Add the following contents to your newly created 'Program.php' file:<code><?
class tables_Program {}
</code><nowiki><p>
In other words, you are creating a class named 'tables_Program'. The above delegate class doesn't do anything yet, but it is a start.
The fun part doesn't start until you start defining methods in your delegate class. There are prescribed interfaces that you will need to implement to make this work.</p></nowiki>


===Example 1: Creating a custom title for records===
The ""Title"" of a record is a string that represents the record. It is used by Xataface in the navigation controller (forward and back buttons) and in the ""Jump"" menu as well as various places around the interface for referring to that record. As an example, take a look at this partial screen shot of the 'details' tab in a Xataface application.

[[Image:http://framework.weblite.ca/documentation/tutorial/getting_started/getTitle-1.gif]]

I have circled the parts of the interface that use a record's title in some way. (1), (2), and (4) show the title of the current record and (3) shows the title of the next record in the found set. You will notice that the title is just the value of the first field in the Program record. In fact, the way that Xataface generates titles is by selecting the first VARCHAR or CHAR field in the table to be the Title for records of that table. In the above example this seems like a good choice, but it may not always be what you want.

We can use our delegate class to customize the way that these titles are generated. By defining a method named getTitle(), we can customize the way that titles are generated. Let's add such a method to our delegate class as follows:
<code>
<?
class tables_Program {

	function getTitle(&$record){
		return $record->val('ProgramName').' Program';
	}
}
</code>

OK, you are probably wondering what this $record object is. The $record object is a Dataface_Record object that represents a record of the 'Program' table (if you want to take a look at the source code for this class it can be found in the 'Dataface/Record.php' file). This object allows you to access all of the information about the record so that you can generate a title for the record. 

The 'val' method simply returns the value of a field in the record.
In the above example, we are telling Xataface that the title of all records of the 'Program' table is the value of the ProgramName field with the string 'Program' appended to it. For example, if the ProgramName of a record was 'Foo', then its title woud be 'Foo Program'.

Lets take a look at our application now to see the changes that we have made.

[[Image:http://framework.weblite.ca/documentation/tutorial/getting_started/getTitle-2.gif]]

Notice that the (1) now has 'Program' appended to the end of the title, but (2) and (3) do not. This is because (2) and (3) are part of the result controller (for navigating through results in the table) and it needs to be able to load hundreds of record titles at a time, but the getTitle() method requires that the entire record be loaded into memory for it to work which would be unfeasible when we need the title of hundreds of records. The result controller titles can also be customized, however, using the titleColumn() method, which simply returns the name of the column that should be used as the title. It can also return MySQL clauses that are equivalent to a column name (e.g., CONCAT('FirstName', ' ', 'LastName') would be valid).

Okay, let's add a titleColumn() method to our delegate class so that we can customize the way our records are represented in the result controller:

<code>
<?
class tables_Program {

	function getTitle(&$record){
		return $record->val('ProgramName').' Program';
	}
	
	function titleColumn(){
		return 'AdmissionDeadline';
	}
}
</code>


All that the titleColumn method does is return the name of a column to be used as the title for records of the 'Program' table. In this case, we making the 'AdmissionDeadline' field the title column which results in the result controller looking like this:

[[Image:http://framework.weblite.ca/documentation/tutorial/getting_started/titleColumn-1.gif]]


This was a simple example, but it is possible to do more with the titleColumn() method than just specify the name of a column. Any valid MySQL calculation that can be placed in a SELECT list can be returned here. For example, we can make use of the MySQL 'CONCAT' function to append the string 'Program' to the 'ProgramName' field and achieve the same results as our previous getTitle() method:

<code>
<?
class tables_Program {

	function getTitle(&$record){
		return $record->val('ProgramName').' Program';
	}
	
	function titleColumn(){
		return ""CONCAT(ProgramName, ' Program')"";
	}
}

</code>

And now we can see the changes in our application:

[[Image:http://framework.weblite.ca/documentation/tutorial/getting_started/titleColumn-2.gif]]

It may seem a little bit inconvenient to have to define 2 methods to effectively customize the title of a record. Future versions may attempt to address this issue so that one or the other can be implemented, but for now, both methods must be implemented to effectively customize the title. In addition, future versions will likely add the 'titleColumn' functionality to an INI file since it is more or less static.

===Summary===

In this section we learned how to add a delegate class to our tables to customize the behavior of our applications. Delegate class become more important when you need very fine-grained customizations to your application, as you will see in later sections. One important feature of delegate classes is the ability to add security permissions to tables and records to limit who can view, edit, and delete certain records. This will be covered in the next section.

","delegate classes,getTitle,getPermissions",en,
GettingStarted:triggers,81,Triggers,"==Triggers==

Triggers are methods that can be defined to carry out custom behaviors when certain events occur in the application (e.g., when records are saved, inserted, or deleted).

Triggers are generally regarded as one of the more advanced features of database applications. Despite the ""advanced"" status of triggers, however, they are very simple to use and can be leveraged by Xataface developers to add powerful functionality to their applications.

So what can you do with a trigger?

* Send a confirmation email every time a new record is inserted into a table.
* Delete records related to a record that is being deleted (to maintain the consistency of the database).
* Add custom logging functionality.
* Add extra permissions or validation rules (although these are probably better handled with the validation framework).

You can really do just about anything you want with a trigger. A trigger is essentially just a custom PHP method that is called by Xataface when certain events occur.

===What triggers are available?===

As of version 0.5.3 Xataface supports the following triggers:

* '''beforeSave''' : called just before a record is saved (either inserted or updated).
* '''afterSave''' : called just after a record is saved (either inserted or updated).
* '''beforeInsert''' : called just before a record is inserted.
* '''afterInsert''' : called just after a record is inserted.
* '''beforeUpdate''' : called just before a record is updated.
* '''afterUpdate''' : called just after a record is updated.
* '''beforeDelete''' : called just before a record is deleted.
* '''afterDelete''' : called just after a record is deleted.
* '''beforeAddRelatedRecord''' : called just before a related record (new or existing) is added to a relationship.
* '''afterAddRelatedRecord''' : called just after a related record (new or existing) is added to a relationship.
* '''beforeAddNewRelatedRecord''' : called just before a new related record is added.
* '''afterAddNewRelatedRecord''' : called just after a new related record is added.
* '''beforeAddExistingRelatedRecord''' : called just before an existing related record is added.
* '''afterAddExistingRelatedRecord''' : called just after an existing related record is added.

===How do you define a trigger?===

Triggers are always defined as methods of the delegate class for a table. As an example, suppose we wanted to add a trigger to send a the administrator a notification email every time a new record is inserted into the 'Course' table. The steps would be as follows:

# Create a delegate class for the 'Course' table (if one does not already exist) by creating a file named 'Course.php' inside the 'tables/Course' directory.
# Add the following to the Delegate class file to make it a valid delegate class:<code><?
class tables_Course {}
</code>
# Okay, we want our trigger to be called every time a record is inserted. There are 2 possible triggers that can be defined, then:<nowiki>
<ul>
<li>beforeInsert</li>
<li>afterInsert</li>
</ul>
<p>In this case it is probably more appropriate to define the afterInsert trigger because we really only want to send the notification email after the insert has successfully taken place. Therefore, we will define the afterInsert() method in our delegate class as follows:</p>
</nowiki><code>
<?
class tables_Course {
	....
    /**
     * Trigger that is called after Course record is inserted.
     * @param $record Dataface_Record object that has just been inserted.
     */
    function afterInsert(&$record){
        mail('admin_email@yourdomain.com','Subject Line', 'Message body'); 
    }
}
</code>
# That's all for now. The afterInsert() method defined above will automatically be called every time a record is inserted into the Course table. This method, as we have defined it, will send a notification email to the administrator email.

===Sending feedback to the user===

The above example sends the email without any feedback to the application's user of whether the email succeeded or not. When the user inserts a new Course he will only see that the record was succesfully saved, but no mention is made of the email. The following example does the same thing as the previous one, except that it sends a confirmation to the user when the email has been successfully sent:
<code>
function afterInsert(&$record){
    $response =& Dataface_Application::getResponse();
        // get reference to response array

    if ( mail('shannah@sfu.ca', 'Subject Line', 'Message Body') ){
        $response['--msg'] .= ""\nEmail sent to shannah@sfu.ca successfully."";
    } else {
        $response['--msg'] .= ""\nMail could not be sent at this time."";
    }
}
</code>

Now, when the user inserts a new record he will see a confirmation as follows:

[[Image:http://framework.weblite.ca/documentation/tutorial/getting_started/trigger-after-insert-confirm.gif]]

Notice that we used the Dataface_Application::getResponse() function to obtain a reference to the application's response array. The response array is just a global array that is shared by the entire application that allows you to pass information easily from one part of the application to another. The '--msg' index of array is where you can place text that you wish to have displayed to the user as a confirmation.

'''Note''': It is important to use '=&' to assign the result of Dataface::getResponse() and not just '='. e.g.:
<code>
$response =& Dataface_Application::getResponse(); // correct!
$response = Dataface_Application::getResponse(); // WRONG!!
</code>

This is because we need a reference to the response array, not a copy. That way when we assign a value to the '--msg' index it is applied to the actual response array and not a copy of it.

===Handling Errors===

The above method of sending messages to the user is useful for notifications and confirmations. However, in some cases you want to inform the user that an error occurred and cancel further operations. For example you may want to disallow a record to be inserted if a confirmation email cannot be sent. In this case we define the beforeInsert() trigger and return a PEAR_Error object if the email fails as follows:
<code>
<?
class tables_Course {
    function beforeInsert(&$record){
        $response =& Dataface_Application::getResponse();
        if ( mail('shannah@sfu.ca', 'Notification', 'Your record was created')){
            $response['--msg'] .= ""\nEmail sent successfully to shannah@sfu.ca"";
        } else {
            return PEAR::raiseError(
                ""Errors occurred while sending email.  Record could not be inserted"",
                 DATAFACE_E_NOTICE
            );
        }
    }
     
}
</code>

This trigger is called just before a course record is inserted into the database. If the mail succeeds, then the user sees a success message. If it fails, on the other hand, the insert is cancelled, and the user will see a message as follows:

[[Image:http://framework.weblite.ca/documentation/tutorial/getting_started/trigger-error.gif]]


'''Note''': Notice the use of the DATAFACE_E_NOTICE constant as a second parameter for PEAR::raiseError(). This is important as without it Xataface will display a less user-friendly error message complete with stack trace. If the error is such that you want a complete stack trace, you can use the DATAFACE_E_ERROR constant instead.","triggers, beforeSave, afterSave, beforeInsert, afterInsert,sending email",en,
Creating_Printable_Reports,82,"Creating a Custom Printable Report","==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'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's sorting and searching preferences.  E.g. if the user searches for only books about ""frogs"", 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 ""products"" 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'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's directory.  It might be a good idea to create a directory to store your images if you haven't already.  An appropriate name might by ''images''.  For this example, we'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's [[actions.ini file]] so that Xataface knows about our action, and where we want its icon to be displayed.  We'll start out with a basic definition that just specifies the icon for the action, and the ''category'' of the action.

<code>
[printable_report]
    icon=""{$site_url}/images/printer.png""
    category=result_list_actions
    description=""See this product list in a printable format""
</code>

The ''result_list_actions'' 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 ""list"" tab, you'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't see this icon, but see the text ""printable_report"" instead, then you have entered an incorrect path to the icon in the ''icon'' directive.  If you don't see an icon at all or any text, then your ''category'' directive may be incorrect.  Check that it is exactly ""result_list_actions"".

If you mouse over your icon you'll see the text that you specified as your ''description'' directive for the action:

[[Image:http://media.weblite.ca/files/photos/Picture%20-6.png?max_width=640]]

You'll notice, if you try to click on your icon, that nothing happens.  This is because we haven't yet specified a URL for your action.  We'll wait to specify our URL, until we'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'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 ''actions'' directory named after our action:
 %APPLICATION_PATH%/actions/printable_report.php

with the following contents:

<code>
<?php
class actions_printable_report {
    function handle(&$params){
    	echo ""Hello world!!!"";
    }
}
</code>

Please note the following about this snippet:

# The action was placed in a file ''actions/printable_report.php'' because the action is named ''printable_report'' (referring to our definition in the ''[[actions.ini file]]''.  If the action was named ''foo'', then we would place our action in file ''actions/foo.php''.
# The ''printable_report.php'' file contains a single class named ''actions_printable_report'' after the name of the action.
# The action class contains a single method ''handle'' which handles the request for the action (i.e. outputs the report the way we like).  This method must exist and me named exactly ''handle''.
# The ''handle'' method takes a single ''&$params'' parameter which contains some parameters that may be passed to the action.  We won't be dealing with these in this example.


Before proceeding, let's try accessing our action just to make sure that we're on the right track.  Point your browser to 
 http://example.com/yourapplication/index.php?-action=printable_report

Note that you don't point our web browser directly to your action php file (in the ''actions'' directory.  Rather you point it to your application's entry point (index.php file), and specify the action via the ''-action'' 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's build onto our action now.  First we will load the found set of records as follows:

<code>
<?php
class actions_printable_report {
    function handle(&$params){
    	$app =& Dataface_Application::getInstance();
    	$query =& $app->getQuery();
    	
    	if ( $query['-table'] != 'products' ){
    		return PEAR::raiseError('This action can only be called on the Products table.');
    	}
    	
    	$products = df_get_records_array('products', $query);
    	
    }
}
</code>

Things to note in this snippet:

# We start be loading a reference to the ''Dataface_Application'' object.
# We then use the ''Dataface_Application'' 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 ''-table'' and ''-action''.
# In our particular action we are designing it to only work for the ''products'' 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 ''-skip'' and ''-limit'' 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 ""Next"" in list view, you see '-skip' and '-limit' parameters automatically added to the URL.

''df_get_records_array'' 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 ''$query'' array before passing it to ''df_get_records_array''.  E.g.:

<code>
$query =& $app->getQuery();
$query['-skip'] = 0;
$query['-limit'] = 10000;
$products = df_get_records_array('products', $query);
</code>


====Looping through and Printing Product Info====

Now comes the fun part.  We're just going to loop through our found set and print off the product information:

<code>


foreach ($products as $p){
	

	echo '<table>'
		.'<tr><th>Product ID</th><td>'.$p->htmlValue('product_id').'</td></tr>'
		.'<tr><th>Product Name</th><td>'.$p->htmlValue('product_name').'</td></tr>'
		.'<tr><th>Description</th><td>'.$p->htmlValue('product_description').'</td></tr>'
		.'<tr><th>Photo</th><td>'.$p->htmlValue('product_image').'</td></tr>'
		.'</table>';
}

</code>


The entire action at this point will look like:

<code>

<?php
class actions_printable_report {
    function handle(&$params){
    	$app =& Dataface_Application::getInstance();
    	$query =& $app->getQuery();
    	$query['-skip'] = 0;
		$query['-limit'] = 10000;
		
    	if ( $query['-table'] != 'products' ){
    		return PEAR::raiseError('This action can only be called on the Products table.');
    	}
    	
    	$products = df_get_records_array('products', $query);
    	foreach ($products as $p){
	

			echo '<table>'
				.'<tr><th>Product ID</th><td>'.$p->htmlValue('product_id').'</td></tr>'
				.'<tr><th>Product Name</th><td>'.$p->htmlValue('product_name').'</td></tr>'
				.'<tr><th>Description</th><td>'.$p->htmlValue('product_description').'</td></tr>'
				.'<tr><th>Photo</th><td>'.$p->htmlValue('product_image').'</td></tr>'
				.'</table>';
		}
    	
    }
}
</code>

Now we refresh our action in the web browser, or point the browser again to:
 http://example.com/yourapplication/index.php?-action=printable_report&-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'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:

<code>
echo '<html><head>'
	.'<title>Printable Report</title>'
	.'<style type=""text/css"">'
	.'	th { vertical-align: top}'
	.'</style>'
	.'</head>'
	.'<body>';
	
	//...
	


</code>

So our finished action looks like:


<code>
<?php
class actions_printable_report {
    function handle(&$params){
    	$app =& Dataface_Application::getInstance();
    	$query =& $app->getQuery();
    	$query['-skip'] = 0;
		$query['-limit'] = 10000;
		
    	if ( $query['-table'] != 'products' ){
    		return PEAR::raiseError('This action can only be called on the Products table.');
    	}
    	
    	$products = df_get_records_array('products', $query);
    	
    	
    	
    	echo '<html><head>'
			.'<title>Printable Report</title>'
			.'<style type=""text/css"">'
			.'	th { vertical-align: top}'
			.'</style>'
			.'</head>'
			.'<body>';
    	foreach ($products as $p){
	

			echo '<table>'
				.'<tr><th>Product ID</th><td>'.$p->htmlValue('product_id').'</td></tr>'
				.'<tr><th>Product Name</th><td>'.$p->htmlValue('product_name').'</td></tr>'
				.'<tr><th>Description</th><td>'.$p->htmlValue('product_description').'</td></tr>'
				.'<tr><th>Photo</th><td>'.$p->htmlValue('product_image').'</td></tr>'
				.'</table>';
		}
		
		echo '</body></html>';
    	
    }
}
</code>



===Connecting the Icon to the Action===

FInally it is time to connect our Icon to our Action.  We do this by adding a ''url'' directive for the action in the ''[[actions.ini file]]'':


<code>
[printable_report]
    icon=""{$site_url}/images/printer.png""
    category=result_list_actions
    description=""See this product list in a printable format""
    url=""{$app->url('-action=printable_report')}""
</code>

Explanation of the ''url'' directive in this snippet:

* The ''url'' method of the ''[[Dataface_Application]]'' object is used to generate a URL with the user's current query settings, but with the ''-action'' parameter set to ''printable_report''.

Now if we reload our application, go to the list tab of the ''products'' 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 ''products'' table it probably isn't a good idea to make the icon visible for every other table.  For example, if you go to the list view of the ''users'' table, you'll see the printer icon in the top right just like it appears for the ''products'' 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 ''condition'' directive for our action to hide it from tables other than the ''products'' table as follows:

 condition=""$query['-table'] == 'products'""
 
So our action will now look like:

<code>
[printable_report]
    icon=""{$site_url}/images/printer.png""
    category=result_list_actions
    description=""See this product list in a printable format""
    url=""{$app->url('-action=printable_report')}""
    condition=""$query['-table'] == 'products'""
</code>

Now if you reload the list for the ''users'' table you'll notice that the printer icon is now gone.  But returning to the ''products'' table shows our action still alive and well.

===Locking Down our Action with Permissions===

In our case we don'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 ''reports'' 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:
<code>
[printable_report]
    icon=""{$site_url}/images/printer.png""
    category=result_list_actions
    description=""See this product list in a printable format""
    url=""{$app->url('-action=printable_report')}""
    condition=""$query['-table'] == 'products'""
    permission=reports
</code>

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 ""Access Denied"" message.

",,en,
Key,83,"fields.ini Directive: Key","The '''Key''' directive is used only when the table is a view and you need to explicitly define which columns are part of the primary key.  For example, if we created a view on the books table to only show books in a given year as follows:
<code>
create view books_2000 as
select * from books where year='2000'
</code>

And we wanted to use this view as a table in our Xataface application we would need to tell it that the primary key of this view is the book_id field.  So in the fields.ini file we would add:

<code>
[book_id]
    Key=PRI
</code>

Note that this is case sensitive.  key=PRI will not work.

===Compound Primary Keys===

For primary keys comprising multiple columns we would add this directive for each field in the key.  E.g. if our books_2000 view had 2 fields in the primary key, say author_id and book_index, we would have in the books_2000 fields.ini file:
<code>
[author_id]
    Key=PRI

[book_index]
    Key=PRI
</code>

Links:
* [http://xataface.com/forum/viewtopic.php?f=4&t=6723 Lookup widget on view with compound primary key]

Return to [[fields.ini file]]","Key, Views, MySQL Views, Create View, PRI, Primary Keys",en,
http://xataface.com/documentation/how-to/site_with_backoffice_How_to_build_a_site_with_a_backoffice_,84,"A site with a backoffice","==A site with a backoffice==
To create a site with a backoffice for the administrator, so that the visitors do not have to log in to read the pages, you add this code in the ApplicationDelegate.php file in the conf directory :
<code>

function getPermissions(&$record){
    if ( isAdmin() ) return Dataface_PermissionsTool::ALL();
    else return Dataface_PermissionsTool::READ_ONLY();
}
 
</code>
",,en,
http://xataface.com/documentation/how-to/site_with_backoffice,85,"How to build a site with an optional login form","==How to build a site with an optional login form==
To publish a public site with data without any need to login to access, here is the code :
<code>
function getPermissions(&$record){
    if ( isAdmin() ) return Dataface_PermissionsTool::ALL();
    else return Dataface_PermissionsTool::READ_ONLY();
} 
</code>
In this way, you still can login to administrate your data.",,en,
site_with_backoffice,86,,"==How to build a site with an optional login form==
To publish a public site with data without any need to login to access, here is the code :
<code>
function getPermissions(&$record){
    if ( isAdmin() ) return Dataface_PermissionsTool::ALL();
    else return Dataface_PermissionsTool::READ_ONLY();
} 
</code>
In this way, you still can login to administrate your data.",,en,
sql_delegate_method,87,"__sql__ Delegate Method","return to [[Delegate class methods]]

===Synopsis===

The __sql__ delegate class method can be defined in any delegate class to specify the SQL query that should be used to fetch records for a given table.  This method overrides the [[__sql__]] directive of the fields.ini file.  This strategy is primarily used to graft columns from another table onto the base table.

=====Use Caution=====

This is an advanced feature and, if used incorrectly, can muck up your application. Make sure that your SQL query includes a superset of the columns in the base table, and is a row-for-row match for the rows in the base table.  I.e. you should never use an internal join.  Always use a left join so that all of the rows of the base table are returned even if the join table doesn't have a corresponding row.

If you want to simply filter a table's records, and don't need to graft any additional columns onto the table, you should use the [[setSecurityFilters]] method.

===Example===

Given the table foo, its delegate class:

<code>
class tables_foo {
    function __sql__(){
        return ""select f.*, c.category_name from foo f left join categories c on f.category_id=c.category_id"";
    }
}
</code>

This effectively grafts a column ""category_name"" onto the foo table based on a join with the categories table.

","__sql__, SQL queries, delegate class",en,
secure,88,"secure fields.ini directive","[[fields.ini file]] directive used only with [[container fields]].  If this flag is set, then the field contents will be treated in a secure manner and will obey the application permissions.  If this directive is not set, then uploaded files in [[container fields]] are served directly by the web server without considering application permissions.  Setting this directive will cause the application use a special get_blob action to serve the uploaded file, and this obeys application permissions.

==Example==

Given a field to upload a PDF report, your [[fields.ini file]] section for this field might be something like:

<code>
[pdf_report]
    Type=container
    allowed_extensions=""pdf""
    savepath=""uploads""
    url=""uploads""
</code>


Now if we upload a file named ""foo.pdf"" in this field, it will be uploaded to:
 http://www.example.com/path/to/myapp/uploads/foo.pdf

Now we change the field definition to use the secure directive:

<code>
[pdf_report]
    Type=container
    allowed_extensions=""pdf""
    savepath=""uploads""
    url=""uploads""
    secure=1
</code>

In this case it will still upload files to the ''uploads'' directory, but all of the links generated in the Xataface interface (and via the ''display()'' and ''htmlValue()'' methods) will be for a URL like:
  http://www.example.com/path/to/myapp/index.php?-action=getBlob&-table=mytable&-field=pdf_report&record_id=10

Which will serve up the PDF file as an attachment.

===Restricting Direct Access to uploads directory===

Note: You still need to restrict access to the uploads directory or it may be possible for users to still guess the absolute URL to files in it.  You can restrict access by placing an .htaccess file in the uploads directory (if you are using Apache) with the following contents:
<code>
deny from all
</code>

If you are using IIS or another web server you should look into the methods available for you to restrict access to directories.

===HTTP Response Codes===

The [[getBlob action]] will return the following HTTP Response Codes:

* '''404''' - If either the record does not exist, or the record's specified container field is empty.
* '''403''' - If the current user doesn't have permission to access this record.
* '''500''' - If there is another error.  The actual error will be written to the error log.","secure,fields.ini file",en,
file,89,,"==Dynamic select boxes==

To create two select boxes whose one is dependent (slave) of the other (master), we need to use some javascript with Jason.

Create the valuelists.ini:
<code>

;valuelist for the slave
[slaves_list]
__sql__ = ""select slave_id, slave_name, master_id from slaves""

; valuelist for the masters
[masters_list]
__sql__ = ""select master_id,master_name from masters""
</code>

fields.ini:
<code>
[master]
vocabulary=masters_list

[slave]
vocabulary=slaves_list
</code>

delegate class in the table directory :
<code>
...
function block__after_new_record_form(){
echo <<<END
<script language=""javascript""><!--
var slave_field= document.getElementById('slave');
var master_field = document.getElementById('master');
END;
// Let's get all the slaves available.
$app =& Dataface_Application::getInstance();
$query =& $app->getQuery();
$table =& Dataface_Table::loadTable($query['-table']);
$slaves = $table->getValuelist('slaves_list');
$slave_masters = $table->getValuelist('slaves_list__meta');
// Note that the slaves_list__meta valuelist is automatically created
// because we had three columns in the slaves valuelist.
// The first and third columns effectively create a 2nd valuelist
// named 'slaves_list__meta'

// $slaves is an array with keys slave_id and values slave_name
// slave_masters is an array with keys slave_id and values master_id

import('Services/JSON.php');
$json =& new Services_JSON(); // A JSON encoder to allow us to easily
// convert PHP arrays to javascript arrays.
echo '
var slaves_options = '.$json->encode($slaves).';
var slaves_master = '.$json->encode($slave_masters).';
';

echo <<<END
master_field.onchange = function(){
var selected_master = master_field.options[master_field.selectedIndex].value;
slave_field.options.length = 0;
var index = 0;
for ( slave_id in slaves_options){
if ( selected_master == slaves_master[slave_id] ){
slave_field.options[index++] = new Option(slaves_options[slave_id], slave_id);
}
}
};
//--></script>
END;
}

// Also place this javascript after an edit record form...
function block__after_edit_record_form(){
return $this->block__after_new_record_form();
}


</code> ",,en,
Dynamic_select_boxes,90,,"==Dynamic select boxes==

To create two select boxes whose one is dependent (slave) of the other (master), we need to use some javascript with Jason.

Create the valuelists.ini:
<code>

;valuelist for the slave
[slaves_list]
__sql__ = ""select slave_id, slave_name, master_id from slaves""

; valuelist for the masters
[masters_list]
__sql__ = ""select master_id,master_name from masters""
</code>

fields.ini:
<code>
[master]
vocabulary=masters_list

[slave]
vocabulary=slaves_list
</code>

delegate class in the table directory :
<code>
...
function block__after_new_record_form(){
echo <<<END
<script language=""javascript""><!--
var slave_field= document.getElementById('slave');
var master_field = document.getElementById('master');
END;
// Let's get all the slaves available.
$app =& Dataface_Application::getInstance();
$query =& $app->getQuery();
$table =& Dataface_Table::loadTable($query['-table']);
$slaves = $table->getValuelist('slaves_list');
$slave_masters = $table->getValuelist('slaves_list__meta');
// Note that the slaves_list__meta valuelist is automatically created
// because we had three columns in the slaves valuelist.
// The first and third columns effectively create a 2nd valuelist
// named 'slaves_list__meta'

// $slaves is an array with keys slave_id and values slave_name
// slave_masters is an array with keys slave_id and values master_id

import('Services/JSON.php');
$json =& new Services_JSON(); // A JSON encoder to allow us to easily
// convert PHP arrays to javascript arrays.
echo '
var slaves_options = '.$json->encode($slaves).';
var slaves_master = '.$json->encode($slave_masters).';
';

echo <<<END
master_field.onchange = function(){
var selected_master = master_field.options[master_field.selectedIndex].value;
slave_field.options.length = 0;
var index = 0;
for ( slave_id in slaves_options){
if ( selected_master == slaves_master[slave_id] ){
slave_field.options[index++] = new Option(slaves_options[slave_id], slave_id);
}
}
};
//--></script>
END;
}

// Also place this javascript after an edit record form...
function block__after_edit_record_form(){
return $this->block__after_new_record_form();
}


</code> 

The 2.0 version has a [http://xataface.com/dox/modules/depselect/latest| depselect module] to produce cascading dynamic select boxes very simply.",,en,
setSecurityFilters,91,"setSecurityFilter() method","== Example ==

In the delegate class for the users table:

<code>
<?php
class tables_users {
    function init(&$table){
        if ( !isAdmin() ){
            $table->setSecurityFilter(array('group_id'=>10));
        }
    }
}
</code>

This will only set the filter on non-admin users (assuming that you have defined a function isAdmin() to tell you if the current user is an admin user.",,en,
Authenticating_Against_the_PHPBB_Users_table,92,"Authenticating Against the PHPBB Users Table","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 ('''assuming that our PHPBB is set up in the same database as our Xataface app''') by doing the following:

# Set up the [_auth] section of the [[conf.ini file]] as follows:<code>
[_auth]
users_table = phpbb_users
username_column = username
password_column = user_password
</code>
# Set up the user_password field to use md5 encryption in the ''tables/phpbb_users/fields.ini'' file <code>
[user_password]
encryption=md5
</code>

That'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:<code>
[_auth]
users_table = phpbb_users
username_column = username
password_column = user_password
</code>
# Implement the user_password__serialize() method in your phpbb_users delegate class (i.e. the ''tables/phpbb_users/phpbb_users.php'' file):<code>
<?php
class tables_phpbb_users {
	

	function user_password__serialize($password){
		$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
		$sql = ""select user_password from phpbb_users where username='"".addslashes($_POST['UserName']).""'"";
		$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->_hash_crypt_private($password, $row['user_password'], $itoa64);
		return $hash;
	}
	
	
	/**
	* The crypt function/replacement
	*/
	function _hash_crypt_private($password, $setting, &$itoa64)
	{
		$output = '*';
	
		// Check for correct hash
		if (substr($setting, 0, 3) != '$H$')
		{
			return $output;
		}
	
		$count_log2 = strpos($itoa64, $setting[3]);
	
		if ($count_log2 < 7 || $count_log2 > 30)
		{
			return $output;
		}
	
		$count = 1 << $count_log2;
		$salt = substr($setting, 4, 8);
	
		if (strlen($salt) != 8)
		{
			return $output;
		}
	
		/**
		* We're kind of forced to use MD5 here since it'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 >= 5)
		{
			$hash = md5($salt . $password, true);
			do
			{
				$hash = md5($hash . $password, true);
			}
			while (--$count);
		}
		else
		{
			$hash = pack('H*', md5($salt . $password));
			do
			{
				$hash = pack('H*', md5($hash . $password));
			}
			while (--$count);
		}
	
		$output = substr($setting, 0, 12);
		$output .= $this->_hash_encode64($hash, 16, $itoa64);
	
		return $output;
	}
	
	/**
	* Encode hash
	*/
	function _hash_encode64($input, $count, &$itoa64)
	{
		$output = '';
		$i = 0;
	
		do
		{
			$value = ord($input[$i++]);
			$output .= $itoa64[$value & 0x3f];
	
			if ($i < $count)
			{
				$value |= ord($input[$i]) << 8;
			}
	
			$output .= $itoa64[($value >> 6) & 0x3f];
	
			if ($i++ >= $count)
			{
				break;
			}
	
			if ($i < $count)
			{
				$value |= ord($input[$i]) << 16;
			}
	
			$output .= $itoa64[($value >> 12) & 0x3f];
	
			if ($i++ >= $count)
			{
				break;
			}
	
			$output .= $itoa64[($value >> 18) & 0x3f];
		}
		while ($i < $count);
	
		return $output;
	}

	

}
</code>","PHPBB, authentication, security, authentication modules",en,
Authenticating_Against_the_Joomla!_Users_Table,93,,"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.
<code>[_auth]
users_table = jos_users
username_column = username
password_column = password</code>
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 : 
<code>8NdiRqLRKLHaNwudJ3InJknsew9sc7pL</code>
2 - concate the clear entered password with the random key
example : 
<code>password8NdiRqLRKLHaNwudJ3InJknsew9sc7pL</code>
3 - doing a md5 encryption on the result string
example : 
<code>md5(password8NdiRqLRKLHaNwudJ3InJknsew9sc7pL = f2b1fb3996442db549c1ed1a1eebbfe1</code>
4 - concate the md5 string with the random key separated by "":""
example :
<code>f2b1fb3996442db549c1ed1a1eebbfe1:8NdiRqLRKLHaNwudJ3InJknsew9sc7pL</code>
So it's a great encryption but xataface doesn'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 :
<code><?
class tables_jos_users {
	
function password__serialize($password){

   $app =& Dataface_Application::getInstance(); 
   $query = ""SELECT id, gid, block, password, usertype FROM jos_users where username='"".$_POST['UserName'].""'"";
   $result = mysql_query($query,$app->db()) or die(""Query failed"" . mysql_error() );

   $line = mysql_fetch_array($result, MYSQL_ASSOC);
   mysql_free_result($result);

   $arraypass=explode("":"", $linea['password']);
   $key=$arraypass[1];
   
   $ret = md5(trim($password).$key)."":"".$key;
   return $ret;
} 
}
?></code>
Save your file and test the result.
Enjoy ! ;-)","joomla authentication md5",en,
fieldname__validate,94,"fieldname__validate Delegate Class Method","Return to [[Delegate class methods]]

[[toc]]

===Synopsis===

Xataface allows you to add validation on any particular field in table by adding a fieldname__validate method to the table's delegate class of the form:
<code>
function myfield__validate(&$record, $value, &$params){
    if ( $value != 'Steve' ){
        $params['message'] = 'Sorry you must enter ""Steve""';
        return false;
    }
    return true;
}
</code>

===Parameters===

* &$record : A [http://dataface.weblite.ca/Dataface_Record Dataface_Record] object encapsulating the record we are validating.  Note that the values of this object correspond with the submitted values from the form, and not necessarily the actual values of the record in the database.
* $value : The value that is being inserted.
* &$params : An output array that can be used to pass back a message if validation fails.  You would set this array's 'message' parameter to be a message.

===Returns===

Returns a boolean value.  True if the value is ok and false if validation failed.

===See Also===

* [[validators]] - For simple validation rules you can use the [[validators|validator:VALIDATOR_NAME]] directive of the [[fields.ini file]].
* [http://xataface.com/documentation/tutorial/getting_started/validation Form Validation] - Section on form validation in the Getting Started tutorial.

","validate, validation, delegate class validation, custom validator",en,
validators,95,"validators:NAME fields.ini directive","Return to [[fields.ini file]]

[[toc]]

===Synopsis===

In the fields.ini file you can specify validation rules to be applied to any field by adding the validators:NAME directive in that field's section of the [[fields.ini file]].

===Available Validators===

{| class=""listing listing2""
|-
! Name
! Description
! Value
! Version
|-
| required
| Field is required
| 1
| All
|-
| maxlength
| Maximum number of characters allowed.
| $length
| All
|-
| minlength
| Minimum number of characters allowed.
| $length
| All
|-
| rangelength
| Range (min and max) characters allows
| $min,$max
| All
|-
| email
| Input must be syntactically correct email address.
| 1
| All
|-
| emailorblank
| Accepts an email address or a blank field.
| 1
| All
|-
| regex
| Input must match the provided regular expression.
| A regular expression
| All
|-
| lettersonly
| Input must contain only letters (i.e. [a-zA-Z]
| 1
| All
|-
| numeric
| The input must contain a valid positive or negative integer or decimal number.
| 1
| All
|-
| nopunctuation
| The input must not contain any of these characters: <nowiki>( ) . / * ^ ? # ! @ $ % + = , "" ' &gt; &lt; ~ [ ] { }.</nowiki>
| 1
| All
|-
| nonzero
| The input must not begin with zero.
| 1
| All
|-
| uploadedfile
| The element must contain a successfully uploaded file.
| 1
| All
|-
| maxfilesize
| The uploaded file must be no more than $size bytes.
| $size
| All
|-
|filename
| The uploaded file must have a filename that matches the regular expression $file_rx.
| $file_rx
| All
|}


===Examples===

To make a the first_name field required we add the following to the [[fields.ini file]]:
<code>
[first_name]
    validators:required=1
</code>

'''Note that fields that are declared NOT NULL in the database are required by default.'''.  If you wanted to remove the ''required'' validator from a field that is NOT NULL in the database you would add the following to the [[fields.ini file]]:
<code>
[first_name]
    validators:required=0
</code>

===See Also===

* [[fieldname__validate]] - For more complex validation you can define the [[fieldname__validate]] method in the [[Delegate class methods|Table Delegate Class]].
* [http://www.devarticles.com/c/a/Web-Graphic-Design/Using-HTML-Quickform-for-Form-Processing/12/ HTML_QuickForm article] going over HTML_Quickform validation.  Dataface's forms are built on HTML_QuickForm.
* [http://xataface.com/documentation/tutorial/getting_started/validation Form Validation] - Section from getting started tutorial introducing form validation in a tutorial format.

","validation, form validation, validators,validator:name",en,
validators:VALIDATOR_NAME:message,96,"validators:VALIDATOR_NAME:message directive for the fields.ini file","Return to [[fields.ini file]]

[[toc]]

===Synopsis===

If you want to customize the error message associated with a particular [[validator|validation rule]] you can use the validators:VALIDATOR_NAME:message directive in the fields.ini file.

===Format===

<code>
[myfield]
    validators:VALIDATOR_NAME:message = MESSAGE
</code>

===Examples===

If you don't like the default error message that is displayed when you make the first_name field required, you can customize it with your own message.  E.g.
<code>
[first_name]
    validators:required=1
    validators:required:message = ""Please enter your first name""
</code>

===See Also===

* [[validators]] - The [[fields.ini file]] directive for adding a validation rule to a field.  This directive must be used in conjunction with [[validators]].
* [[fieldname__validate]] - For more complex validation rules you can define them in the table delegate class.
* [http://xataface.com/documentation/tutorial/getting_started/validation Form Validation] - Section in the Getting Started tutorial on form validation.","validation messages,error messages,form validation rules",en,
_auth,97,"_auth section of the conf.ini file","[[conf.ini file|Return to conf.ini file]]

[[toc]]

===Synopsis===

The ''_auth'' section of the conf.ini file includes configuration directives to enable authentication in a Xataface application.  For more information about authentication and registration see [[authentication]].  This section may include the following directives:

===Directives===

{| class=""listing listing2""
|-
! Directive
! Description
! Required
! Default
! Version
|-
| users_table
| The name of the table that contains your user accounts.
| Yes
| None
| 0.6
|-
| username_column
| The name of the column that stores the username.
| Yes
| None
| 0.6
|-
| password_column
| The name of the column that stores the password.
| Required if using basic authentication.
| None
| 0.6
|-
| auth_type
| Specifies the authentication module that is being used.  E.g. basic, cas, ldap, http, facebook, etc...
| No
| basic
| 0.6
|-
| allow_register
| Flag to enable user registration.  If this is set to 1, then a ''register'' link will appear below the login form.
| No
| 0
| 0.8
|-
| session_timeout
| Number of seconds of inactivity after which the user will be logged out. Note: Arithmetic don't work in the conf.ini, use seconds.
| No
| 86400 (=> 24*60*60 (24 hours))
| 1.3rc4
|}

===See Also===

* [[authentication]] - Overview of Xataface Authentication
* [[conf.ini file]] - Directives available in the conf.ini file.","_auth,authentication,conf.ini file,allow_register",en,
registration_form,98,"Setting up User Registration","[[toc]]

===Synopsis===

Xataface optionally enables you to allow users to register for an account in your application.  If your ''users'' table includes a column for email, it will also perform email validation before the account is activated.  Before tackling user registration, it is good to have an understanding of Xataface's [[authentication]] and [http://xataface.com/documentation/tutorial/getting_started/permissions permissions] faculties.

===Enabling Registration===

To enable registration, simply add the following to the ''[[_auth]]'' section of the [[conf.ini file]]:

<code>
allow_register=1
</code>

e.g. after adding this, your ''[[_auth]]'' section might look like:

<code>
[_auth]
     users_table=users
     username_column=username
     password_column=password
     allow_register=1
</code>

After doing this, you'll notice a little ''Register'' link below the login form.  

[[Image:http://media.weblite.ca/files/photos/Picture%2036.png?max_width=640]]

Clicking on this link will produce a registration form for the user which is essentially a ""New Record"" form on your ''users'' table.

[[Image:http://media.weblite.ca/files/photos/Picture%2037.png?max_width=640]]

Some features of this registration form include:

* Checks to ensure that the username is unique
* If the users table contains an ''email'' field, it will use the user-entered address for email validation before activation is complete.

===Setting up Permissions to Support Registration===

'''Xataface <= 1.2.4''':   You must ensure that unlogged-in users have permission to add new records to the ''users'' table.  This means that your getPermissions() method on the users table should, at least, provide the ''new'' permission.  In addition these users must be granted the ''register'' permission in order to be able to register to begin with.

'''Xataface >= 1.2.5''':  You no longer need to provide the ''new'' permission to allow users to register.  You simply need to provide the ''register'' permission.

====Sample Permissions on Users Table====

In the tables/users/users.php file (assuming my ''users'' table is actually named ""users"")

<code>
class tables_users {

    function getPermissions($record){
        if ( isAdmin() ) return null;
        $perms['register'] = 1;
        return $perms;
     
    }
}
</code>

'''Note that this example is only applicable for Xataface 1.2.5 or higher.  In Xataface 1.2.4 you needed to provide users with the ''new'' permission rather than the ''register'' permission, which opens up a small security hole since users could potentially just use the ""new"" action if they new the URL and by-pass the registration and activation email altogether'''.

Some notes on this example:

* The isAdmin() function is not part of Xataface.  It is used as a bit of *magic* here to reduce code.  It is supposed to simply return true if the currently logged in user is an admin.  Hence if the user is an admin, this method defers to the Application Delegate class's permissions (i.e. this method should not affect administrators).
* We are giving all users (logged in or not) the register permission which enables them to register for an account on the system.
* Generally you will want to restrict permissions on some of the fields in the users table.  E.g. users should not be able to set their role or access level when they register.  You can define more fine-grained permissions on these fields using the [[fieldname__permissions]] method of the users table delegate class (per the following example).

====Restricting Permissions on Particular Fields====

You probably don't want users to be able to set their access level when the register for an account, and your ""users"" table will quite often contain some field like ""role"" which stores this information.  So the previous example is not quite realistic.  You will also need to restrict permissions on the ""role"" field (and any other fields that you want to prevent users from setting themselves.

<code>
function role__permissions(&$record){
    if ( isAdmin() ) return null;
    return Dataface_PermissionsTool::NO_ACCESS();
}
</code>

This will cut off the user's ability to set their own role when they register.  You will likely want to set the default role value either in the mysql table definition or in the [[beforeInsert]] trigger.

===Email Validation===

As mentioned above, registration works by sending an activation email to the address specified in the user's registration.  This email contains a link back to the ''activate'' action of your Xataface application, which will create the user account and log the user in.  This implies that your ''users'' table must store an email address for your users.  If you add a field named ''email'' to the ''users'' table, Xataface will assume that you mean to use this field as the user's email address, and thus, for email validation.  However you can override this functionality and use *any* field as an email field by setting the ''email'' directive of the appropriate field in the [[fields.ini file]] for the ''users'' table.

'''Example: Assigning the my_addr field of the users table to be used for email validation''':

In the tables/users/fields.ini file:
<code>
[my_addr]
    email=1
</code>

====Disabling Email Validation====

99% of the time, email validation is the preferred way of ensuring that people who register are who they say they are.  You may, however, prefer to let users register directly without requiring the email activation step.  You can disable email validation by overriding the ''register'' action in the [[actions.ini file]] as follows:

In your application's [[actions.ini file]]:
<code>
[register > register]
    email_validation=0
</code>

After setting this, the user account will automatically be created, and the user logged in upon saving the registration form.

===Triggers: Overriding Registration Workflow===

Xataface provides a number of triggers in the [[Application Delegate Class]] to override and extend the behavior of the user registration and activation process.  For a list of available triggers see [[Application Delegate Class#registration]].


===Preventing Spam with CAPTCHA===

One problem with enabling automatic registration is that it invites SPAM in the form of bots that can learn how to automatically register for user accounts and then leave unwanted input into your application.  The Xataface [[reCAPTCHA module]] allows you to avoid these problems to some extent by forcing users who aren't logged in to fill a CAPTCHA field in order to successfully submit the form.  This is especially helpful for registration forms.

After installing the [[reCAPTCHA module]] the registration form will include a CAPTCHA field like the one depicted below:

[[Image:http://media.weblite.ca/files/photos/Picture%2038.png?max_width=640]]

For more information about the reCAPTCHA module [[reCAPTCHA module|click here]].
    ","registration form, _auth, authentication",en,
reCAPTCHA_module,99,"The reCAPTCHA module","[[toc]]

===Synopsis===

The Xataface reCAPTCHA module CAPTCHA support to any Xataface form that is rendered to the public (i.e. when users are not logged in).  This is particularly useful for the [[registration form]] as a means of spam prevention.   Below is a screenshot of a registration form with the reCAPTCHA module installed:

[[Image:http://media.weblite.ca/files/photos/Picture%2038.png?max_width=640]]

For more information about reCAPTCHA see [http://recaptcha.net/].


===Installation===

# Download/extract the module directory into your xataface/modules directory.  Currently this module is only available in SVN (http://weblite.ca/svn/dataface/modules/reCAPTCHA/trunk/)
# Add the following to the <nowiki>[_modules]</nowiki> section of your [[conf.ini file]].<code>
[_modules]
    modules_reCAPTCHA=modules/reCAPTCHA/reCAPTCHA.php
</code>
# Add the following section to your conf.ini file.<code>
[reCAPTCHA]
    public_key=""xxxxxxx""
    private_key=""xxxxxxx""
</code> Where public_key, private_key are your keys from your reCAPTCHA account. '''(Note that you need to register for a free reCAPTCHA account at [http://recaptcha.net/] in order for this to work.'''

===Usage===

If you are NOT logged in, you will now see a reCAPTCHA validation image before the submit button for all webforms in your Xataface application.  If you fail to enter the captcha text correctly the form will not validate.  If you are logged in this module has no effect.

===See Also===

* [[registration_form|Enabling User Registration in Xataface]]
* [[modules|Xataface Modules]]
","captcha, registration, validation",en,
Introduction_to_the_Xataface_API,101,"Introduction to the Xataface API","Back to [http://xataface.com/wiki the wiki]

[[toc]]

===Synopsis===

Xataface is provides an API to help in developing your own custom actions.  This API includes objects and functions to more easily interact with the database (i.e. search, edit, delete, and save records), build forms, use templates, and more.  This section of the wiki endeavors to highlight some of the more useful and commonly used aspects of the API.

===The dataface-public-api.php Facade===

Much of the functionality provided by the Xataface API is wrapped up easy-to-use functions which are made available in the dataface-public-api.php script, which is always present in a Xataface application (it is loaded at the beginning of your index.php file).

===Some Common Tasks===

====Loading a Single Record from the Database====

<code>
// Load record from 'people' table matching person_id=10
$record = df_get_record('people', array('person_id'=>10)); 

// Load record from people table with first_name 'John' and last_name 'Smith' 
$record2 = df_get_record('people', array('first_name'=>'=John', 'last_name'=>'=Smith'));

// $record and $record2 are Dataface_Record objects.
echo ""Loaded Person: "".$record->val('person_id').
      "" named "".$record->val('first_name').' '.$record->val('last_name');
</code>

In the above examples we load a [http://dataface.weblite.ca/Dataface_Record Dataface_Record] object and use the val() method to display particular field values.

The 2nd arguments of df_get_record() is an array which serves as a query.  See [[URL Conventions]] for more examples of the types of queries that you can provide here.

====Loading a set of records from the Database====

<code>
//  Load the first 30 canadians from the people table
$people = df_get_records_array('people', array('nationality'=>'=canadian'));
foreach ( $people as $person){
    // $person is a Dataface_Record object
    echo ""<br>Person "".$person->val('person_id')."" is named "".$person->val('first_name');
}
</code>

'''Caveat:  Note that when loading records using df_get_records_array() it only loads a preview of each record for memory's sake.'''  A preview of the record is the same as a full record except that all fields are truncated to be less than 255 characters.  If you have long text fields that you need to load, then these will be truncated.  There are a few different solutions if you need to load the entire contents of a long field, including:

* Use df_get_record instead.  (This is only preferable if you are only loading a single record).
* Use the [[struct]] [[fields.ini file]] directive on the field to designative the field contents as a 'stucture' that should never be truncated.
* Use the extended form of ''df_get_records_array()'' with the 5th parameter (preview) set to false.  E.g. <code>
$people = df_get_records_array('people',array(), null, null, false);
</code>

====Editing and Saving a Record====

<code>
$person = df_get_record('people', array('person_id'=>10));

// Using setValue() to set a single field value.
$person->setValue('first_name', 'Peggy');

// Using setValues() to set multiple field values at once
$person->setValues(array('first_name'=>'Peggy', 'last_name'=>'Sue'));

// Commit the changes to the database
$person->save();
</code>

","xataface api, df_get_record, df_get_records_array, Dataface_Record, Editing, Saving, Loading, Searching",en,
before_authenticate,102,"before_authenticate hook","Return to [[Application Delegate Class]]

The '''before_authenticate''' hook is a method that can be defined in the [[Application Delegate Class]] which is called before the authentication step occurs on '''every''' 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===

<code>
/**
 * Implemented trigger to be called before authentication to set the authentication
 * type to basic.
 */
function before_authenticate(){
    $auth = Dataface_AuthenticationTool::getInstance();
    if ( @$_SESSION['-login-type'] == 'basic' ) $auth->setAuthType('basic');
}
</code>

In the above example we used a separate action to store the user'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]].",authentication,en,
Customizing_Theme_Based_on_IP_Address,103,"Customizing Theme Based on IP Address","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'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's network).

To implement this behavior we need to solve one issue.

'''How do we store a range of IP addresses in the database so that they can be queried easily to match if the user's IP address falls in that range.'''
	
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:

<code>
$intIP = ip2long($_SERVER['REMOTE_ADDR']);
$sql = sprintf('select * from ip_blocks where start_ip<=%u and end_ip>=%u', $intIP, $intIP);
... etc....
</code>

'''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.'''
	
For the above query, we assuming a table with a definition like:

<code>
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)
)
</code>
	
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's action.

e.g.

<code>
class conf_ApplicationDelegate {
	function beforeHandleRequest(){
		$app = Dataface_Application::getInstance();
		
		// Get a reference to the current query so we can
		// alter it if necessary.
		$query =& $app->getQuery();
		
		
		// Get the user's IP address and covert it to a long int.
		$intIP = ip2long($_SERVER['REMOTE_ADDR']);
		$sql = sprintf('select `theme` from ip_blocks where start_ip<=%u and end_ip>=%u', $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't find any valid IP ranges, let's redirect the
		// user to a different action to let them know that
		// they're not welcome here.
		if ( !$row ){
			$query['-action'] = 'not_welcome';
				// This assumes that we have defined an action
				// called ""not_welcome""
				
			return;
		}
		
		$theme = $row[0];
		$themePath = 'themes/'.basename($theme);
		// Check that the theme exists.
		if ( $theme and file_exists($themePath) ){
			df_register_skin($theme, $themePath);
		}
	}
}
</code>

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:

<code>
<?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->getValue());
		if ( $val !== false ){
			return sprintf('%u', $val );
		}
		return null;
	}
	
	function start_ip__pullValue($record, $el){
		$val = $record->val('start_ip');
		if ( $val )
			return long2ip($val);
		return $val;
	}
	
	function end_ip__pushValue($record, $el){
		$val = ip2long($el->getValue());
		if ( $val !== false ){
			return sprintf('%u', $val );
		}
		return null;
	}
	
	function end_ip__pullValue($record, $el){
		$val = $record->val('end_ip');
		if ($val){
			return long2ip($val);
		}
		return $val;
	}
	
	
}
</code>

The [[field__pullValue]] and [[field__pushValue]] method should be inverses of each other.

'''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.'''
	

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:

<code>
function start_ip__display($record){
	$val = $record->val('start_ip');
	if ( $val )
		return long2ip($val);
	return $val;
}

function end_ip__display($record){
	$val = $record->val('end_ip');
	if ($val){
		return long2ip($val);
	}
	return $val;
}
</code>

==References==

* [http://xataface.com/documentation/how-to/how-to-define-custom-serialization-for-fields How to define custom serialization for fields]
","ip address, pullValue, pushValue, beforeHandleRequest",en,
field__pullValue,104,"field__pullValue delegate class method","[[toc]]

The field__pullValue() delegate class method can be used to transform database from the database for use in an edit/new record form.  Sometimes it is the case that we want users to be able to work with data differently than it is stored in the database.

This method should always be accompanied by a corresponding [[field__pushValue]] method which performs the inverse operation and is used to transform the value in an edit form into a format that can be stored in the database.

===Example===

Given a field ''start_ip'' that stores an IP address in the database as an unsigned INT, we want to be able to work with the data on the edit form in a friendlier format - the standard IP address dot notation, so we define pullValue and pushValue methods for the field in the table's delegate class.

<code>
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->getValue());
		if ( $val !== false ){
			return sprintf('%u', $val );
		}
		return null;
	}
	
	function start_ip__pullValue($record, $el){
		$val = $record->val('start_ip');
		if ( $val )
			return long2ip($val);
		return $val;
	}
}
</code>

==References==

* [[Delegate class methods]]
* [[Application Delegate Class]]
* [[http://dataface.weblite.ca/Dataface_Record Dataface_Record API docs]
* [http://xataface.com/documentation/how-to/how-to-define-custom-serialization-for-fields How to define custom serialization for fields] - A how-to document.
","pushValue, pullValue",en,
field__pushValue,105,,"[[toc]]

The field__pushValue() delegate class method can be used to transform a field value as entered in the edit form into a format that can be stored in the database..  Sometimes it is the case that we want users to be able to work with data differently than it is stored in the database.

This method should always be accompanied by a corresponding [[field__pullValue]] method which performs the inverse operation and is used to transform the value in the database into a format that can be edited in the edit form.

===Example===

Given a field ''start_ip'' that stores an IP address in the database as an unsigned INT, we want to be able to work with the data on the edit form in a friendlier format - the standard IP address dot notation, so we define pullValue and pushValue methods for the field in the table's delegate class.

<code>
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->getValue());
		if ( $val !== false ){
			return sprintf('%u', $val );
		}
		return null;
	}
	
	function start_ip__pullValue($record, $el){
		$val = $record->val('start_ip');
		if ( $val )
			return long2ip($val);
		return $val;
	}
}
</code>

==References==

* [[Delegate class methods]]
* [[Application Delegate Class]]
* [[http://dataface.weblite.ca/Dataface_Record Dataface_Record API docs]
* [http://xataface.com/documentation/how-to/how-to-define-custom-serialization-for-fields How to define custom serialization for fields] - A how-to document.
","pullValue, pushValue",en,
__global__,106,"__global__ section for the fields.ini file","Return to [[fields.ini file]]

[[toc]]

===Synopsis===

The fields.ini file supports a __global__ section that applies to all fields in the current table.  This is particularly useful for setting up default functionality that you wish to see on all fields except a few.  For example you may wish to have all fields hidden from list view by default, and only explicitly enable a few.  Same for CSV export or the details form.

===Example 1: Hiding All Fields from List View===

In the fields.ini file:
<code>
[__global__]
    ;; hide all of the fields from list view
    visibility:list=hidden

[first_name]
    ;; show the first name in list view 
    visibility:list=visible

[last_name]
    visibility:list=visible

;;.... etc....
</code>

In the above example we used the __global__ section to declare that we want all fields to be hidden from list view by default.  Then we explicitly showed first_name and last_name in list view. In this case only first_name and last_name will appear in the list view.

==See Also==

*[[fields.ini file]]
*[[visibility:list]]","__global__, fields.ini, visibility:list",en,
beforeHandleRequest,107,"beforeHandleRequest Application Delegate Class Method","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===

<code>
class conf_ApplicationDelegate {
	
	function beforeHandleRequest(){
		$app = Dataface_Application::getInstance();
		$query =& $app->getQuery();
			// Make sure you assign by reference (i.e. =& )
			// for this if you want to make changes to the query
			
		if ( $query['-table'] == 'dashboard' and $app->_conf['using_default_action'] ){
			$query['-action'] = 'my_default_action';
		}
	}
}
</code>

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'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]]
* '''[[Customizing Theme Based on IP Address]]''' - Article containing an example of using beforeHandleRequest hook.","beforeHandleRequest, Application Delegate",en,
beforeAddRelatedRecord,108,"beforeAddRelatedRecord Delegate Class Method","Return to [[Delegate class methods]]

[[toc]]

==Synopsis==

The ''beforeAddRelatedRecord'' delegate class method can be implemented in any table's delegate class.  It will be executed before any related record is added to that table'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==

<code>
function beforeAddRelatedRecord( Dataface_RelatedRecord $record );
</code>

==Parameters==

* '''$record''' - 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.

<code>
function beforeAddRelatedRecord($record){
    if ( /* some checks here */ ){
        return Dataface_Error::permissionDenied('Sorry you don\'t have permission to do this.');
    }
}
</code>

==Examples==

===Example 1: Permission Check===

<code>
function beforeAddRelatedRecord($record){
    if ( $record->_relationshipName == 'program_roles' ){
        // check to make sure that we are allowed to add roles to this program
        $program = df_get_record('programs', array('program_id'=>'='.$record->val('program_id')));
        if ( !$program ){
            return Dataface_Error::permissionDenied(""Program could not be found"");
        }
        if ( !$program->checkPermission('add new related record', array(
                'relationship' => 'program_roles'
                )
             )
           ){
            return Dataface_Error::permissionDenied(""You don't have permission to add roles to this program"");
        }
    }
}
</code>

The above example requires a little bit of context to understand.  This method is defined in the 'users' table.  There is a relationship between the ''users'' table and the ''programs'' table called 'program_roles'.  It keeps track of the roles that users have with respect to programs.  There is a mirror relationshp in the ''programs'' table that goes to the ''users'' table, also named ''program_roles''.  Both the ''users'' table and the ''programs'' table contain rel_program_roles__roles() methods to define who can and cannot add to this relationship.  However these don'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 ''users'' table we defined the ''beforeAddRelatedRecord'' 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
","beforeAddRelatedRecord, Delegate class methods, relationship triggers",en,
beforeSave,109,"beforeSave Trigger","Back to [[Delegate class methods]]

[[toc]]



===Synopsis===

The beforeSave trigger can be implemented in any table'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===

<code>function beforeSave( Dataface_Record $record);</code>

====Parameters====

# '''$record''' - 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 ""people"", suppose we wanted to automatically populate a field named ""full_name""  with the concatenation of the ""first_name"" and ""last_name"" fields.  (Note you could also achieve a similar thing by making a calculated field for ""full_name"", 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 ""full_name"" field every time the record is saved.

In the ""people"" table delegate class (i.e. tables/people/people.php)
<code>
class tables_people {
    function beforeSave($record){
        $record->setValue('full_name', 
            $record->val('first_name').' '.$record->val('last_name')
        );
    }
}
</code>

==See Also==

* [http://www.xataface.com/documentation/tutorial/getting_started/triggers Triggers section of the Xataface Getting Started Tutorial]
","triggers, beforeSave,",en,
Contribute_to_Xataface_Translation_Project,110,"How to Contribute Translations","[[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. '''NOTE: THIS IS NOT THE PREFERRED WAY TO CONTRIBUTE TRANSLATIONS.  PLEASE SEE ""Adding Translations Using Google Spreadsheets"" BELOW'''.

==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===

<code>
scripts.GLOBAL.FORMS.OPTION_PLEASE_SELECT = ""Please Select ...""
save_button_label = ""Save""
scripts.GLOBAL.MESSAGE.PERMISSION_DENIED = ""Permission Denied""
scripts.GLOBAL.NO_RECORDS_MATCHED_REQUEST = ""No records matched your request.""
</code>

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:

<code>
scripts.GLOBAL.FORMS.OPTION_PLEASE_SELECT = ""SVP sélectionnez ...""
save_button_label = ""Enregistrer""
scripts.GLOBAL.MESSAGE.PERMISSION_DENIED = ""Permission Refusée""
scripts.GLOBAL.NO_RECORDS_MATCHED_REQUEST = ""Aucun résultat ne correspond à votre requête.""
</code>

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.

'''NOTE: IT IS BETTER TO USE GOOGLE SPREADSHEETS TO EDIT TRANSLATIONS, THAN TO WORK WITH INI FILES DIRECTLY. PLEASE SEE ""Adding Translations Using Google Spreadsheets"" BELOW'''


==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't have to worry about this).

===Wrap Translations in Double Quotes===

All translations should be wrapped in double quotes.  E.g.
<code>
mykey=""My Value""
</code>

If you forget to close a quote, it will likely cause a parse error and Xataface will fail to load the file.  E.g.
<code>
mykey=""My Value
</code>
would be a problem.


===Can't Use Double Quotes as Part of the Translation===

Since INI files use double quotes to wrap strings, you can't use a double quote inside your translation.  E.g. you can't do this:
<code>
mylink=""<a href=""http://google.com"">Google</a>""
</code>
because of the inline double quotes.

One way around this is to try to use single quotes where possible.  E.g.
<code>
mylink=""<a href='http://google.com'>Google</a>""
</code>

Another way around this is to the ''""_Q""'' key sequence, which Xataface will
automatically convert to a double quote for you at runtime.  E.g. You could do:
<code>
mylink=""<a href=""_Q""http://google.com""_Q"">Google</a>""
</code>

'''NOTE: If you use Google Spreadsheets to edit your translations, you won'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.'''


===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:
<code>
No action found = ""No action found named '$name'""
</code>
has the variable ''$name''.

So the French translation should maintain this variable.  E.g. in the fr.ini file:
<code>
No action found = ""Aucune action nommée '$name'""
</code>


==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&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'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't have to worry about encoding issues, and you don'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:
<code>
'Help!', I exclaimed
</code>
If you unfocus from that cell it will only say:
<code>
Help!', I exclaimed
</code>
If you go back into edit mode of the cell again, you'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.:
<code>
''Help!', I exclaimed
</code>

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've contributed a number of translations to the [https://spreadsheets.google.com/ccc?key=0AqJNZUI7flxSdFVLWDlnVVpQZ3dMaGZhVjVHN2c3bEE&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 ''File'' > ''Download as'' > ''CSV (Current Sheet)'' 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:
<code>
$ php /path/to/xataface/tools/csv2ini.php /path/to/xataface-translations.csv /path/to/destination/dir/
</code>

This will convert the xataface-translations.csv file into a set of language INI files and place them the specified destination directory  (don'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.

'''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.'''




","Translations, Google Spreadsheets, en.ini, fr.ini",en,
Relationship_Permissions,111,"Relationship Permissions","[[toc]]

==Synopsis==

As relationships are a core feature of Xataface, it is helpful to understand how to handle permissions on related records.  Even if you apply permissions to every table individually, you need to take into account the relationships that you have defined between tables, because they may open access to actions that you did not intend.

For example, suppose we have two tables: ''people'' and ''publications'', and we have a relationship from ''publications'' table to the ''people'' table called ''publication_authors''.

Suppose you give a user write access to a record of the publications table, but no access to the people table.  If you are allowing the ''add new related record'' permission on the ''publications'' table record, then the user will still be able to add new people, via the ""Add related people record"" function of the database.  This may or may not be desirable.

This article discusses the issues that arise due to relationships and permissions, and how to deal with them.

==Relationship Permissions==

The Xataface [[permissions.ini file]] defines a handful of permissions that are related to the management of related records.  These include:

{| class=""listing listing2""
|-
! Name
! Description
! Included in Roles
|-
| [[add new related record]]
| Permission to add a new related record to a relationship.
| EDIT, DELETE, OWNER, ADMIN, MANAGER
|-
| [[add existing related record]]
| Permission to add an existing record to a relationship.
| EDIT, DELETE, OWNER, ADMIN, MANAGER
|-
| [[remove related record]]
| Permission to remove a record from a relationship.  (This only allows removing a record from the relationship - not deleting the record from the database, so this is only really relevant in a many-to-many relationship).
| EDIT, DELETE, OWNER, ADMIN, MANAGER
|-
| [[delete related record]]
| Permission to delete a related record.  This allows both removing the related record from the relationship, and deleting the record from the database.   This permission is not included in any default roles.  A combination of permission for [[remove related record]] in the source table and [[delete]] in the target table, are equivalent to access to this permission.  Use this permission only when you need to override the ability to delete records from the database based on membership in a relationship.
| -
|-
| [[view related records]]
| Permission to view the records of a relationship.
| READ ONLY, EDIT, DELETE, OWNER, ADMIN, MANAGER
|-
| [[related records feed]]
| Permission to access the RSS feed of a relationship.
| READ ONLY, EDIT, DELETE, OWNER, ADMIN, MANAGER
|}


==Fine-grained, Per-relationship Permissions==

You may often find that defining a flat set of permissions to all relationships on a record is insufficient for your purposes, because some relationships may demand different access levels than others.  You can override the permissions for any particular relationship by implementing the [[rel_relationshipname__permissions]] method in the table's delegate class, where ''relationshipname'' is the name of the relationship.

e.g.  Consider the relationship ''manufacturers'':
<code>
function rel_manufacturers__permissions($record){
	// $record is a Dataface_Record object
	return array(
		'view related records' => 0
	);
}
</code>
This will tell xataface that users should not be able to view related records on the ''manufacturers'' relationship.  This will override any permissions that were defined in the [[getPermissions]] method.


==More Complete Example==

In the following example, we design a products database.  We use 2 relationships on our products table:  One to keep track of the parts that are used in our product.  The other to keep track of the users that are allowed to edit our products.

We want to make it so that only the product owner can manage the editors for a product, but anyone in the product_editors relationship is allowed to edit the product or add/remove parts from the product.

We don't want to give any users access directly to the parts, product_parts, or product_editors tables.  We want all access to go through the relationships on the products table.

===Database/Relationship Design===

Consider a database with 4 tables:

# products (product_id, product_name, owner_username)
# parts (part_id, part_name)
# product_parts (part_id, product_id)
# product_editors (product_id, editor_username)
# users (username, password, role)

And we have the following relationships on the ''products'' table:

<code>
[parts]
    parts.part_id=product_parts.part_id
    product_parts.product_id=""$product_id""

[editors]
    product_editors.product_id=""$product_id""
</code>


===Application Permissions : Very Restrictive===

Like a good boyscout, we define our default permissions in the [[Application Delegate Class]] to be very restrictive: Don't let anyone do anything.

<code>
class conf_ApplicationDelegate {
    function getPermissions($record){
        return Dataface_PermissionsTool::NO_ACCESS();
    }
}
</code>


===Products Table Permissions: Less restrictive===

Now we open it up for our products table in the getPermissions() method of the products delegate class.

In tables/products/products.php:
<code>
class tables_products {
    function getPermissions($record){
        $user = Dataface_AuthenticationTool::getInstance()->getLoggedInUser();
        if ( $user and $record and $record->val('owner_username') == $user->val('username')){
        	// Give the record owner Edit permissions on the product
        	return Dataface_PermissionsTool::getRolePermissions('EDIT');
        }
        
        // Everybody else gets read only access to the products table.
        return Dataface_PermissionsTool::READ_ONLY();
    }
}

</code>

===Checking if the current User is an Editor===

So far we have given the product owner edit permissions and everyone else read only permissions.  We still need to allow editors to edit the product.  In order to do this we need to be able to *efficiently* find out if the current user is an editor of a particular product.  There are a few different ways to do this, but some are better than others.  Some strategies include:

# Perform an SQL query inside the [[getPermissions]] method to see if the user is an editor for the product.  '''THIS IS VERY BAD!!!''' The [[getPermissions]] method should not include any IO or database queries because it is called a large number of times per request... making expensive calls in this method will slow down your app dramatically.
# Create a function to load and cache all of the current user's products so that this can be easily checked at will.  This is fine if the user is expected be able to edit only a few products.  If he could be an editor for thousands of products, this may not be practical as it will cause you to have to load thousands of records into memory on every page request.
# Use the [[__sql__]] method of the delegate class to create a grafted field on the ''products'' table indicating whether the current user is an editor for the product.  This results in a very quick and accessible indicator variable that can be used in the [[getPermissions]] method to check to see if the current user is an editor for the current product.  E.g.  In the tables/products/products.php file (delegate class):<code>
function __sql__(){
    return sprintf(""select p.*, pe.editor_username from products p
                left join product_editors pe on p.product_id=pe.product_id
                where pe.editor_username='%s'"",
                addslashes(
                   Dataface_AuthenticationTool::getInstance()->getLoggedInUsername()
                )
            );
                
}</code>

This will result in a situation where product records will have an additional field ''editor_username'' which will either be blank if the current user is not an editor for the product; or will contain the current user's username if they are an editor for the product.


===Table Permissions for Product Editors===

Now that we have a reliable way to tell, for any given product, whether the current user is, in fact, an editor, we can ammend the [[getPermissions]] method of the products table to include our editor permissions.

<code>
class tables_products {
    function getPermissions($record){
        $user = Dataface_AuthenticationTool::getInstance()->getLoggedInUser();
        if ( $user and $record and $record->val('owner_username') == $user->val('username')){
        	// Give the record owner Edit permissions on the product
        	return Dataface_PermissionsTool::getRolePermissions('EDIT');
        }
        
        if ( $user and $record and $record->val('editor_username') == $user->val('username') ){
            // If the user is an editor, we give them edit permissions
            // also
            return Dataface_PermissionsTool::getRolePermissions('EDIT');
        }
        
        
        if ( $user ){
        // Other logged in users have read only access
            $perms = Dataface_PermissionsTool::READ_ONLY();
            $perms['new'] = 1; // We'll also let them add new products
            return $perms;
	}
	    
	// Regular users just get the default permissions as 
	// defined in the Application Delegate class
	return null;
    }
}

</code>

===Removing Editor Access to the Editor Relationship===

You'll notice that at this point, the product editor has exactly the same permission as the product owner.  They both have permission to add and remove records from all relationships on the product.  However, we don't want them to be able to access the editors relationship at all.  We will use the [[rel_relationshipname__permissions]] method to override the permissions for the ''editors'' relationship.

In the tables/products/products.php delegate class:

<code>

function rel_editors__permissions($record){
    $user = Dataface_AuthenticationTool::getInstance()->getLoggedInUser();
	if ( $user and $record and $record->val('owner_username') == $user->val('username')){
		// Owners should just get their normal permissions
		return null;
	}
	
	if ( $user and $record and $record->val('editor_username') == $user->val('username') ){
		// If the user is an editor, we give them edit permissions
		// also
		return array(
		    'view related records' => 0,
		    'add new related record' => 0,
		    'add existing related record' => 0,
		    'remove related record' => 0,
		    'delete related record' => 0
		    );
	}
	
	// Other users just get their normal permissions
	return null;

}

</code>


===Assigning product owner by default===

With the current permissions, something funny would happen.  Users have permission to add new records, but once the record is added they won't be able to edit it because they are neither an editor nor the owner of the product.  We'll fix this by assigning the current user as the product's owner using the [[beforeSave]] trigger in the products delegate class:

<code>
function beforeSave($record){
	$user = Dataface_AuthenticationTool::getInstance()->getLoggedInUser();
	if ( $user ){
    	$record->setValue('owner_username', $user->val('username'));
    }
}
</code>

===Testing Out Our Solution===

In your testing of the solution, you should find the following:

# Trying to access any table other than the ''products'' table should result in a ''permission denied'' error.
# If you access the ''products'' table, you should be able to see a list of existing products, and the ""Add New Record"" action.
# After you add a new product you should see that you are the product owner.
# As a product owner you should see both the ''parts'' and ''editors'' tabs in your product record.  You should be able to view and add new records to both of these relationships.
# Add another user as an editor to your product, then log in as that user.  You should be able to edit the product, but you shouldn't be able to see the ''editors'' tab for the product.

==See Also==

* [[permissions.ini file]] - Overview of the Xataface permissions.ini file
* [http://xataface.com/documentation/tutorial/getting_started/permissions Getting Started with Xataface Permissions]
* [[How to granulate permissions on each field]] - Brief tutorial on how to set permissions on a field by field basis.
* [[Delegate class methods]] - A list of all of the available delegate class methods that you can implement.  Many of them pertain to permissions and triggers.
* [[Application Delegate Class]] - Overview of the application delegate class.
* [[relationships.ini file]] - The relationships.ini file directives.
","relationships, permissions, rel_relationshipname__permissions, getPermissions, permissions.ini",en,
Module_Developers_Guide,112,"Module Developers Guide","[[toc]]

==Why Write a Xataface Module?==

Xataface modules are components that can be used to extend Xataface's functionality in a generic way so that it can be used on multiple applications.  If you find yourself trying to add the same functionality in multiple applications, you might consider writing a Xataface module so that you can share the functionality more easily.

==What can you do with a Xataface Module==

* Create custom authentication handlers.
* Provide custom actions and templates.
* Implement blocks and slots for existing templates.
* Respond to certain application triggers.


==Where do I place a Xataface Module?==

Xataface modules can be placed in the xataface/modules directory (i.e. DATAFACE_PATH/modules).  As of Xataface 1.3 they can also be placed directly in your application's modules directory (i.e. DATAFACE_SITE_PATH/modules).

==Your first module==

For our first module, we're going to create a simple module that adds ""hello world"" at the beginning of every page.

===Step 1: Create the Module Class===

In your modules directory, create a directory called ""Hello"".  And in this directory, create a file named ""Hello.php"", with the following contents:
<code>
<?php
class modules_Hello  {
}
</code>
(So this file would be located at DATAFACE_PATH/modules/Hello/Hello.php)

===Step 2: Implement the block__before_body method===

We are going to add the phrase ""hello world"" before every page of our application.  The easy way to do this is to fill the [[before_body]] slot of the [[Dataface_Main_Template.html]] template.  We do this by implementing the ''block__before_body'' method in your module (just as we would if we were trying to fill this slot from the [[Application Delegate Class]].

<code>
<?php
class modules_Hello  {
    function block__before_body(){
        echo ""hello world"";
        return true;
    }
}
</code>

===Step 3: Activate the Module===

Xataface only loads the modules that have been enabled in the conf.ini.  We can enable our module by adding the following section to the [[conf.ini file]]:

<code>
[_modules]
modules_Hello=modules/Hello.php
</code>

All this does is tell Xataface that the module class modules_Hello can be loaded from the location modules/Hello.php.

Now if you start up your application, you should see the phrase ""hello world"" written at the top of each page.


==Example 2: Adding a Custom Action==

Our first module shows an example of filling blocks and slots using a module.  Let's now extends that to include a custom action that displays Hello World on its own page.

Complete the following steps:

# Add an ''actions'' directory inside our new module directory.  i.e. modules/Hello/actions
# Add a file named hello.php inside the ''actions'' directory with the following contents:<code>
<?php
class actions_hello {
    function handle($params){
        echo ""Hello World"";
    }
}
</code>
# Go to index.php?-action=hello To see the results of your action.  It should say ""Hello World"" on a blank page.

From here on you can improve this action just as you would if you defined the action inside the application's actions directory.  You can go on to restrict access to this action using permissions, or you could decide to use a template to display the action.

===Defining a Custom ""hello"" permission for our action===

Perhaps we want to create a special permission for our action so that regular users won't have access to this action unless they are specifically granted this permission.  Let's create a ""hello"" permission with which to limit access to our action.

# Create a file named ""permissions.ini"" inside your modules/Hello directory with the following contents:<code>
hello = Permission to access the hello action
</code>

Now if you try to access your action (and you haven't been assigned ALL() permissions) you should receive either a login prompt or a permission denied message.

If you want users to be able to access your action, you will need to explicitly add this permission to one of the user's assigned roles or return it as part of the list of authorized permissions in the getPermissions() method.

===Granting the ""hello"" permission to the ""READ ONLY"" role===

If we want the default READ ONLY role to have access to the ""hello"" permission we can actually modify the READ ONLY role inside the [[permissions.ini file]] that we created inside the Hello module:

<code>
hello = Permission to access hello action

[READ ONLY extends READ ONLY]
    hello=1
</code>


==Example 3: Using Module Templates==

Xataface, by default, stores its templates in the DATAFACE_SITE_PATH/templates and DATAFACE_PATH/templates directories.  However if you are writing a module you probably want to keep templates that are used by the module inside the module directory so that you don't break dependencies when you use the module in different applications.

You can use the [http://dataface.weblite.ca/df_register_skin df_register_skin] method to register additional directories for Xataface to look for templates in.  This will allow you to add a ''templates'' directory inside your module directory for use by your module's templates.

It is probably best to register this directory on demand (i.e. as part of individual actions) rather than register it globally.  

===Using a Template from the hello action===

Let's modify our hello action to use a template that we are going to store and distribute with our module.

# Create a directory named ""templates"" in the modules/Hello directory.
# Create a file named ""hello.html"" inside the templates directory with the following contents:<code>
{use_macro file=""Dataface_Main_Template.html""}
    {fill_slot name=""main_section""}
    	Hello World
    {/fill_slot}
{/use_macro}
</code>  Notice that we are extending the Dataface_Main_Template.html template (which is located in the main Xataface install) so that our hello action can now take on the look and feel of the rest of the application.
# Modify the modules/Hello/actions/hello.php file to look like this:<code><?php
class actions_hello {
    function handle($params){
        df_register_skin('hello theme', dirname(__FILE__).'../templates');
        df_display(array(), 'hello.html');
    }
}
</code>  Notice that we call the df_register_skin function to register the templates directory that we created in the previous step.  Then we call df_display() to display the template.



==See Also===

* [[modules]] - A list of existing Xataface modules that you can download and install.
* [[block__blockname]] - A list of some of the available blocks that can be filled in the default Xataface templates.
* [http://xataface.com/documentation/tutorial/customizing-the-dataface-look-and-feel Customizing Xataface's Look and Feel with Templates] - A tutorial on how to use Xataface's built-in smarty template engine.  It has some sections on using delegate classes to override blocks and slots.
* [http://xataface.com/documentation/tutorial/getting_started/changing-look-and-feel Changing Xataface's Look and Feel] - Part of the Getting Started tutorial that shows how to use slots and blocks to customize the Xataface look and feel.",modules,en,
XataJax,113,"Introduction to XataJax","[[toc]]

Xataface 1.3 comes with a new module [[XataJax]] which comes installed standard.  [[XataJax]] serves as a foundation for Javascript/AJAX powered Xataface applications and will hopefully usher in a new fresh generation of Xataface powered applications.

===Features===

Xataface provides pieces of infrastructure:

# [[XataJax Compiler|A Javascript/CSS Compiler & Linker]]
# A Javascript component library & API

====The Javascript/CSS Compiler & Linker====

Web 2.0 and HTML 5 is a great platform for application development, but it presents a challenge when it comes to developing large-scale, robust applications.  It can be difficult to manage applications that consist of dozens or even hundrends of javascript libraries, some of which depend on each other.

The XataJax compiler provides a solution to this problem by providing a just-in-time compilation of all of the javascripts that are necessary to service a particular request.  It doesn't actually compile your Javascript into machine code, it just aggregates and minifies all of the javascript code together into a single file at runtime so that you don't have to worry about figuring out exactly which libraries you need to import in each template.

This has 2 key benefits:

1. Load time.  By having all of the scripts grouped into a single file, it is much quicker for the client to load the your scripts.

2. Code organization.  Since the compiler will automatically resolve the script dependencies, you can keep your code nicely organized, which produces a far more maintainable source code base.


====The Javascript Component Library & API====

The 2nd part of the XataJax module is a new API that will help you develop rich Web 2.0 applications that interact with your database.  The will allow you to build forms more dyanmically with Javascript, or load, update, and delete records directly using a javascript API.  

The goal is to eventually expose all important Xataface functionality via the XataJax API.

Additional modules may build on top of this API to produce alternative dynamic interfaces for Xataface using existing web UI component libraries like JQueryUI or Sencha.","XataJax, Ajax, Web 2.0",en,
XataJax_Compiler,114,"Introduction to the XataJax Compiler","Return to [[XataJax]]

'''DISCLAIMER''': This page introduces features that require Xataface 1.3 or higher.  At present (Jan. 2011) only Xataface 1.2.6 has been released to the public.

[[toc]]

===Synopsis===

The XataJax compiler is a Javascript CSS compiler and linker that comes with the [[XataJax]] module and will be a standard part of Xataface starting in version 1.3.  It provides a mechanism to process and compile (or so to speak) all of the javascripts required for a page request at the time that the page is requested.  This results in a more scalable, manageable javascript and CSS source base - and in improved performance for your applications.

===Compiler Directives===

{| class=""listing listing2""
|-
! Name
! Description
! Version
|-
| [[xatajax include directive|include]]
| Includes another javascript file inside the current one in place of this directive.  Sample code:<code>//include <myscript.js></code>
| XataJax 0.1 Xataface 1.3
|-
| [[xatajax require directive|require]]
| Includes another javscript file inside the current one only if that file hasn't already been included.  Sample code: <code>//require <myscript.js></code>
| XataJax 0.1 Xataface 1.3
|-
| [[xatajax require-css directive|require-css]]
| Includes a CSS script in the CSS file.  This will will search in the [[Dataface_CSSTool]] include path for the script.  Sample code: <code>//require-css <mystyles.css></code>
| XataJax 0.1 Xataface 1.3
|-
| [[xatajax load directive|load]]
| Loads the specified Javascript file in a separate script tag.  This enables you to reference other scripts without including them in the same bundle, allowing for more effective caching.  Sample code: <code>//load <myscript.js></code>
| XataJax 0.1 Xataface 1.3
|}


===How it Works===

The XataJax compiler works similar to a regular code compiler.  It provides 4 server-side directives to allow you to express dependencies between scripts and stylesheets:

# '''include''' : Includes another javascript file inside the current script in place of the '''include'' directive.
# '''require''' : Includes another javascript file inside the current script (if it hasn't already been included) - i.e. if a script is included twice with a require directive, it will only actually be included once.
# '''load''' : Registers a dependency to another script, but doesn't include it in the same bundle.  This may be used if your script requires code from another javascript, but you don't want it all to be bundled into the same javascript file.  This may help with caching in certain cases.
# '''require-css''' : Registers a dependency to a CSS file.   If your script depends on a CSS file, then it can be registered in this way.


===Brief Example===

''scriptA.js'':
<code>
//require <scriptB.js>
alert('You are in script A');
</code>

''scriptB.js'':
<code>
alert('You are in script B');
</code>

If you loaded ''scriptA.js'', it would actually result in the following javascript being executed:
<code>
alert('You are in script B');
alert('You are in script A');
</code>

Notice that it included ''scriptB.js'' inside script A before the alert of script A.  That is why script B's alert comes first.  Note that this example won't work if you simply try to load scriptA.js directly in Apache.  These directives are only evaluated if the scripts are served by Xataface.  Here is a simple Xataface action that demonstrates how to use this in your Xataface script.

====Creating a custom action====

In your application directory, create an ''actions'' directory if you don't already have one.  Then create a single file named ''hello.php'' with the following content:
<code>
class actions_hello {
    function handle($params){
        $jsTool = Dataface_JavascriptTool::getInstance();
        $jsTool->addPath('js', DATAFACE_SITE_URL.'/js');
        $jsTool->import('scriptA.js');
        echo '<html><head></head><body>'.$jsTool->getHtml().'</body></html>';
        exit;
    }
}
</code>

'''About this code:'''

<code>$jsTool = Dataface_JavascriptTool::getInstance();</code>
We start by obtaining an instance of the JavascriptTool.  This is the object that does all of the magic of compiling your scripts and managing dependencies.

<code>$jsTool->addPath('js', DATAFACE_SITE_URL.'/js');</code>
This line adds the ''js'' directory to the tool's include path, and specifies (with the 2nd parameter) the URL to reach this directory also.  The JavascriptTool works like most source code compilers.  You need to give it the path where it can expect to find its libraries and scripts.  Only paths that you add here will be searched for javascripts.  You can add as many paths as you like.  By default it will have the DATAFACE_PATH/js and the XATAJAX_PATH/js directories in the include path so you can directly reference any scripts in those directories always.

<code> $jsTool->import('scriptA.js');</code>
This is where we declare that we want to use ''scriptA.js'' in the current request.  This line then assumes that the scriptA.js file is located in one of the directories of the current include path.  In our case we make sure that it resides in the DATAFACE_SITE_PATH/js directory.

<code>echo '<html><head></head><body>'.$jsTool->getHtml().'</body></html>';</code>
On this line we simply output the HTML script tags that the javascript tool generates linking to our resulting script.  


Now we can test our our action by going to the page index.php?-action=hello.  If everything worked correctly you should see the appropriate alert dialogs appear  - first telling you you're in Script B, then telling you you're in Script A.  If it doesn't work, you should check your javascript error logs to see what went wrong.

'''NOTE:''' - This simple example actually shows you the step of writing out the HTML tags explicitly with the getHtml() method.  If you are using a standard Xataface template that is based on the Dataface_Main_Template.html template, then this step is unnecessary because the XataJax module will automatically include this HTML just before the closing </body> tag in your pages.



","XataJax, compiler, javascript, css, compiler",en,
Using_RecordGrid,115,"Using RecordGrid","==Xataface RecordGrid Class and Template==

Also see [http://lamp.weblite.ca/dataface-0.6/docs/index.php?-table=Classes&-action=browse&ClassID=30| RecordGrid in the API Doc].


[[toc collapse=0]]

===Introduction===
As we learned in '''[http://xataface.com/documentation/tutorial/getting_started/dataface_actions Actions I: The Basics]''', we can retrieve custom data from the DB in action via queries. This site deals with showing data in tabular form, like it could be received from even such a query. It is done by using Dataface_RecordGrid.


===First Example===
<code>
class actions_testTableAction {

	// Will be called from Xataface, if this action is called
	function handle(&$params){
		$this->app =& Dataface_Application::getInstance();  // reference to Dataface_Application object

		// Custom query
		$result = mysql_query(""select * from testTable"", $this->app->db());
		$body = ""<br /><br />"";
		
		if(!$result)
		{
			// Error handling
			$body .= ""MySQL Error ..."";
		}else
		{
			while($row = mysql_fetch_assoc($result))	// Fetch all rows
			{
				// Maybe do something with the single rows
				$data[] = $row;	// Add singe row to the data
			}
			mysql_free_result($result); // Frees the result after finnished using it

			$grid = new Dataface_RecordGrid($data);	// Create new RecordGrid with the data
			
			$body .= $grid->toHTML();	// Get the HTML of the RecordGrid
		}

		// Shows the content (RecordGrid or error message) in the Main Template
		df_display(array('body' => $body), 'Dataface_Main_Template.html');
	}
}
</code>

You get your data from the query, fetch it into an associative array, create with it an RecordGrid and use the toHTML function. This is sure better than manually create the html tags around the data.

=====Screenshot: Blank RecordGrid=====
<nowiki>
<img src=""http://i89.photobucket.com/albums/k234/horchr/xataface/RecordGrid_blank.png?max_width=610""/>
</nowiki>

=====Screenshot: ResultList=====

<nowiki>
<img src=""http://i89.photobucket.com/albums/k234/horchr/xataface/RecordList.png?max_width=713""/>
</nowiki>


===Colored Example===

As you see above, the resultlist has colored rows, our First Example not. But you can easily change this, when you override the Dataface_RecordGrid.html template:

<code>
<table id=""{$id}"" class=""listing {$class}"">
	<thead>
		<tr>
		{foreach from=$labels item=label}
		<th>{$label}</th>
		{/foreach}
		</tr>
	</thead>
	<tbody>
		{section name=row loop=$data}
		<tr class=""listing {cycle values=""odd,even""}"">
			{foreach from=$columns item=col}
			<td>{$data[row][$col]}</td>
			{/foreach}
		</tr>
		{/section}
	</tbody>
</table>
</code>

The magic happens in <tr class=""listing {cycle values=""odd,even""}"">
The {cycle values=""odd,even""} value cycles these two values and creates so the alternating row classes, like they are in the RecordList. By the way, {cycle ...} is a Smarty Function, see [http://www.smarty.net/docsv2/en/language.custom.functions.tpl| Smarty Doc].

(Find fruther information to template overriding in the tutorial and its links: [http://xataface.com/documentation/tutorial/getting_started/changing-look-and-feel| Changing the Look and Feel])

=====Screenshot: colored RecordGrid=====

<nowiki>
<img src=""http://i89.photobucket.com/albums/k234/horchr/xataface/RecordGrid_colored.png?max_width=610""/>
</nowiki>


===Example completly imitating ResultList===

The Colored Example doesn't look like the ResulList? Its rows aren't as high as theres? That's a styling matter or rather in this case a cause of the checkboxes. Here an example with checkboxes and added (empty) links, so it looks completly like the ResultList:

Change the part in action.php
<code>
			while($row = mysql_fetch_assoc($result))	// Fetch all rows
			{
				// Maybe do something with the single rows
				$row['<input type=""checkbox"">'] = '<input type=""checkbox"">';
				$data[] = $row;	// Add singe row to the data
			}
			mysql_free_result($result); // Frees the result after finnished using it

			$grid = new Dataface_RecordGrid($data,	// Create new RecordGrid with the data
				  array('<input type=""checkbox"">', 'testID', 'name', 'description', 'number'),	
				//Order and selection of the colums
				  null);	// No other labels defined -> it uses keys of the associative array
			
			$body .= $grid->toHTML();	// Get the HTML of the RecordGrid
</code>

Dataface_RecordGrid.html template
<code>
<table id=""{$id}"" class=""listing {$class}"">
	<thead>
		<tr>
		{foreach from=$labels item=label}
		<th><a class=""unmarked_link"">{$label}</a></th>
		{/foreach}
		</tr>
	</thead>
	<tbody>
		{section name=row loop=$data}
		<tr class=""listing {cycle values=""odd,even""}"">
			{foreach from=$columns item=col}
			<td><a class=""unmarked_link"">{$data[row][$col]}</a></td>
			{/foreach}
		</tr>
		{/section}
	</tbody>
</table>
</code>

=====Screenshot: RecordGrid completly imitating ResultList=====

<nowiki>
<img src=""http://i89.photobucket.com/albums/k234/horchr/xataface/RecordGrid_colored_checkboxes_links.png?max_width=610""/>
</nowiki>

=====Screenshot: ResultList=====

<nowiki>
<img src=""http://i89.photobucket.com/albums/k234/horchr/xataface/RecordList.png?max_width=713""/>
</nowiki>

===Try it out===

Use the following code with static test data and any template in this article (or even without overriding it) to try it out.

<code>
class actions_testTableAction {

	// Will be called from Xataface, if this action is called
	function handle(&$params){
		$this->app =& Dataface_Application::getInstance();  // reference to Dataface_Application object

		$result_dummy = array(
			array('testID' => '1', 'name' => 'testname', 
				'description' => 'a short description', 'number' => '258'),
			array('testID' => '2', 'name' => 'another name', 
				'description' => 'a bit longer description to this data set', 'number' => '946'),
			array('testID' => '3', 'name' => 'dummy name', 
				'description' => 'yea, a dummy data set!', 'number' => '1342'),
			array('testID' => '4', 'name' => 'not empty', 
				'description' => 'this data set isn\'t empty ...', 'number' => '282'),
			array('testID' => '5', 'name' => 'your entry', 
				'description' => 'this entry is only for you', 'number' => '79'),
			array('testID' => '6', 'name' => 'no idea', 
				'description' => 'running out of ideas ...', 'number' => '203'),
			array('testID' => '7', 'name' => 'the last one', 
				'description' => 'the end', 'number' => '26841')
		);
		$body = ""<br /><br />"";
		
		foreach($result_dummy as $row)	// Fetch all rows
		{
			// Maybe do something with the singe rows
			$row['<input type=""checkbox"">'] = '<input type=""checkbox"">';
			$data[] = $row;	// Add singe row to the data
		}

		$grid = new Dataface_RecordGrid($data,	// Create new RecordGrid with the data
			array('<input type=""checkbox"">', 'testID', 'name', 'description', 'number'),	
			//Order and selection of the colums
			  null);	// No other labels defined -> it uses keys of the associative array

		$body .= $grid->toHTML();	// Get the HTML of the RecordGrid

		// Shows the content (RecordGrid or error message) in the Main Template
		df_display(array('body' => $body), 'Dataface_Main_Template.html');
	}
}
</code>
","RecordGrid, Dataface_RecordGrid, data in tabular form",en,
getPasswordChangedEmailInfo,121,"getPasswordChangedEmailInfo Application Delegate Class Method","Return to [[Application Delegate Class]]

[[toc]]

===Synopsis===

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. 

Introduced in Xataface 1.3.  Exists in 1.3 or higher.


===Signature===

<code>
function getPasswordChangedEmailInfo(Dataface_Record $user, string $password){}
</code>

===Parameters===

* '''$user''' - The Dataface_Record of the user whose password has been changed.
* '''$password''' - The new temporary password that has been assigned to the user.

===Returns===

This method should return an associative array with 0 or more of the following keys:

* '''subject''' - The subject line of the email.
* '''message''' - The message content of the email.
* '''headers''' - The Email headers (as a string).
* '''parameters''' - Extra parameters for the mail function.

==See Also==

* [[getResetPasswordEmailInfo]] - A delegate class method to define the email that is sent to the user when they request a password reset.  This is the step that immediately precedes the Password Changed email step.","forgot password, reset password",en,
getResetPasswordEmailInfo,122,"getResetPasswordEmailInfo Application Delegate Class Method","Return to [[Application Delegate Class]]

[[toc]]

===Synopsis===

Optional method to define the settings for the email that is sent to the user when they request to reset their password.

Introduced in Xataface 1.3.  Exists in 1.3 or higher.


===Signature===

<code>
function getResetPasswordEmailInfo(Dataface_Record $user, string $reset_url){}
</code>

===Parameters===

* '''$user''' - The Dataface_Record of the user whose password has been changed.
* '''$reset_url''' - The URL where the user should go to reset their password.  When they visit this URL they will receive a message saying that their password has been changed and the new password has been emailed to them.  That subsequent email can be customized using the [[getPasswordChangedEmailInfo]] method.

===Returns===

This method should return an associative array with 0 or more of the following keys:

* '''subject''' - The subject line of the email.
* '''message''' - The message content of the email.
* '''headers''' - The Email headers (as a string).
* '''parameters''' - Extra parameters for the mail function.

==See Also==

* [[getPasswordChangedEmailInfo]] - A delegate class method to define the email that is sent to the user once their password has been reset to a temporary password.  It informs the user of their new temporary password and should include instructions on how to change their password to their own choice.  This step immediately follows the reset password step.","forgot password, reset password",en,
afterCopy,123,"afterCopy Delegate class Method","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===
<code>
function afterCopy( Dataface_Record $original, Dataface_Record $copy);
</code>

===Parameters===

* '''$original''' - The original record that was copied.
* '''$copy''' - 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.
","afterCopy, copy record hook",en,
beforeCopy,124,"beforeCopy Delegate Class Method","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===
<code>
function beforeCopy( Dataface_Record $original, array $values);
</code>

===Parameters===

* '''$original''' - The original record that is to be copied.
* '''$values''' - 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.
","beforeCopy, copy records",en,
getNavItem,125,"getNavItem Application Delegate Class Method","Return to [[Application Delegate Class]]

[[toc]]

===Synopsis===

The getNavItem() method of the application delegate class can be used to override the items that appear in the navigation menu (i.e. the menu that allows users to select the table via either tabs along the top or items along the side).  It should return an associative array with characteristics of the navigation item including the href (i.e. link), label, and selected status.

Using this method it is now possible to have non-table navigation items as well.  You would just add these items to the \[_tables\] section of the [[conf.ini file]] then override the item using this method.

'''Since 1.3'''

====How the Nav Menu Is Built====

Xataface builds the navigation menu by looping through each item in the [_tables] section of the conf.ini file, passing it to the getNavItem() method, and adding the resulting navigation item to the menu.  If getNavItem() returns null, then that item will be skipped.  If getNavItem throws an exception, then the default rendering for the menu item will take place.

===Signature===

<code>
function mixed getNavItem( string $key, string $label ) throws Exception
</code>

===Parameters===

* '''$key''' - The key of the nav item.  In the case of a table, this would be the table name.
* '''$label''' - The label of the nav item (may be overridden).

===Returns===

This method should return either:

# An associative array with the properties of the nav item.
# null to indicate that this nav item should be omitted altogether.  (e.g. if the user shouldn't have permission for it).

If returning an associative array, it should contain the following keys:

* '''href''' - (String) The URL where this nav item should point.
* '''label''' - (String) The label of this nav item.
* '''selected''' - (Boolean) True if the nav item is currently selected.  False otherwise.

===Throws===

If you want to signal Xataface to just use default rendering for the current navigation item you can just throw an exception.  The default rendering will link to the table named ''$key'', and the item's label will be the same as ''$label''.


==Examples==

Given the following conf.ini file:

<code>
...
[_tables]
   people=People
   books=Books
   accounts=Accounts
   reports=Reports

...
</code>

Suppose we want the navigation menu to only show the ''people'' and ''books'' options for regular users.  Admin users can see all options.

In addition, the 'reports' option doesn't correspond with a table of the database.  Instead we are just going to link it to a custom action named 'reports'.

Our getNavItem() method will look something like this:
<code>
function getNavItem($key, $label){
    if (!isAdmin() ){
        switch ($key){
            case 'people':
            case 'books':
                // non-admin users can see these
                throw new Exception(""Use default rendering"");
        }
        // Non-admin users can't see any other table.
        return null;
 
    } else {

        //Admin users can see everything..
        $query =& Dataface_Application::getInstance()->getQuery();
        switch ($key){
            case 'reports':
                // reports is not a table so we need to return custom properties.
                return array(
                    'href' => DATAFACE_SITE_HREF.'?-action=reports',
                    'label' => $label,
                    'selected' => ($query['-action'] == 'reports')
                );
            
        }
        

        // For other actions we need to make sure that they aren't selected
        // if the current action is reports because we want the 'reports'
        // tab to be selected only in that case.
        return array(
            'selected' => ($query['-table'] == $key and $query['-action'] != 'reports')
        );
    }
}
</code>


===See Also===

* [[isNavItemSelected]] - Overrides default behavior of whether a navigation item is currently selected.
   ","getNavItem, navigation menu",en,
getChildren,126,"getChildren Delegate Class Method","Return to [[Delegate class methods]]

[[toc]]

The getChildren() method can be implemented in a table's delegate class to specify the logical ""child"" records of a given record which can be used when creating hierarchical applications.  This method will effectively override the output of the Dataface_Record::getChildren() method for records of this table.

===Signature===

<code>
function getChildren( Dataface_Record $record) : Dataface_Record[]
</code>

===Parameters===

# '''$record''' - The Dataface_Record that is the subject of the query 

===Returns===

This method should return an array of Dataface_Record objects that are considered to be children of the subject record.

===Examples===

<code>
function getChildren($record){
    return df_get_records('webpages', 
        array(
            'parent_id'=>'='.$record->val('webpage_id')
        )
    );
}
</code>


==See Also==

* '''[[getParent]]''' - A Delegate class method to return the logical parent of a given record.","getChildren Delegate class method",en,
meta:class,127,"meta:class relationships.ini file directive","Return to [[relationships.ini file]]

[[toc]]

The ''meta:class'' directive allows you to ascribe special meaning to a relationship which Xataface can use in various parts of your application to provide enhanced capabilities.

For example you can specify a relationship as a ""parent"" relationship, thereby using the relationship to obtain the ""parent"" of records of this table.  This can be used to help build breadcrumbs.

You can also specify a relationship as a ""children"" relationship which would treat records in the relationship as children of the current record.  This can be used in conjunction with the [[list:type]]=treetable directive of the [[relationships.ini file]] to build a tree table that navigates all child records and subtrees.

The Dataface_Record class contains some methods for retrieving the parent and children of records and these methods will take into account any settings you make here.

===Allowed Values===

{| class=""listing listing2""
|-
! Name
! Description
! Version
|-
| parent
| Designates the relationship as a 'parent' relationship, meaning that the first record in this relationship will be treated as the parent of the current record.  This setting can be overridden by the [[getParent]] method of the table delegate class if implemented.
| 0.8
|-
| children
| Designates the relationship as a 'children' relationship meaning that records of the the relationship will be treated as a children.  This setting can be overridden by the [[getChildren]] method of the table delegate class if implemented.
| 0.8
|}


==See Also==

# '''[[list:type]]''' - [[relationships.ini file]] directive to use a treetable for the related record list of a relationship.
# '''[[getChildren]]''' - Delegate class method to explicitly define the Dataface_Record objects that are to be considered as child records of the current record.
# '''[[getParent]]''' - Delegate class method to explicitly define the Dataface_Record object that is to be considered as the parent record of the current record.
",,en,
list:type,128,"list:type relationships.ini file directive","Return to [[relationships.ini file]]

[[toc]]

The list:type directive allows you to override the default list that is used to display related records.  As of Xataface 1.3 there is only one possible value that will have any effect on this directive: ""treetable"".  

Setting
<code>
list:type=treetable
</code>
will cause the related records to be displayed as an expandable/collapsible tree table as shown here:
<nowiki><img src=""http://media.weblite.ca/files/photos/Screen%20shot%202011-04-29%20at%2011.49.33%20AM.png?max_width=640""/></nowiki>

===Prerequisites===

The TreeTable component needs to be able to figure out the logical children of each record in order to know what to show when a row is expanded.  You can use either the [[meta:class]] directive of the [[relationships.ini]] file to specify a relationship as a ""children"" relationship, or you can implement the [[getChildren]] method of the table delegate class to manually define a record's child elements.

==See Also==

* [[getChildren]]
* [[meta:class]]
* [[getParent]]",,en,
fieldname__default,133,"fieldname__default Delegate Class Method","Return to [[Delegate class methods]]

[[toc]]

===Synopsis===

Xataface allows you to pre-populate any particular field in a table by adding a fieldname__default method to the table's delegate class of the form:
<code>
function fieldname__default(){
    return value;
}</code>

Returns the default value for the field fieldname. New record forms will be prepopulated with this value.

===Examples===

<code>
function minimum_bid__default(){
    return 100;
}</code>

<code>
function mydatecol__default(){
    return date('Y-m-d');
}</code>

<code>
function owner_id__default(){
    $auth =& Dataface_AuthenticationTool::getInstance();
    $user =& $auth->getLoggedInUser();
    if ( isset($user) ) return $user->val('userid');
    return null;
}</code>

===See Also===

* [http://xataface.com/forum/viewtopic.php?t=5028 Pre-entered Data] (forum thread) - setting defaults field values on general fields using the fieldname__default delegate class function
* [http://xataface.com/forum/viewtopic.php?t=4004 How to initialize a Date field to today's date?] (forum thread) - alternate methods to use specifically with a date/time field
* [http://xataface.com/forum/viewtopic.php?t=3988 Setting default select setting from users table] (forum thread) - solution to populate the current user","default, initialize, populate, pre-populate, delegate class default",en,
after_action_activate,181,"after_action_activate Delegate Class Method","Return to [[Application Delegate Class]]

[[toc]]


The '''after_action_activate''' 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 '''users''' table.
# The ''after_action_activate'' trigger is called.

===Since===

This hook has been available since Xataface Version 1.2

===Example===

<code>
/**
 * 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 'record'
 * with the Dataface_Record object of the users table with the user that was activated.
 */
function after_action_activate(array $params){
    $user = $params['record'];
    
    mail($user->val('email'), 'Your account is activated', 'Your account has been activated... etc..');
}
</code>

===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.
","Registration, activation, register, activate, users",en,
field__fieldname,141,"Defining Calculated Fields","Return to [[Delegate class methods]]

Xataface allows you to define calculated fields using the delegate class.  These fields won't be visible in the UI by default, but they will be accessible to some modules (e.g. the HTML Reports Module) and they are always accessible to you via the API.

E.g.  If you define a calculated field named ''year'', you would be able to access this value using the regular Dataface_Record syntax:

<code>
$record->val('year');
</code>

You could also define any number of filter methods and permissions on this field just as you can on regular fields.

e.g. <code>
function year__permissions($record){
    // Return special permissions on the year field.
}
</code>

or <code>
function year__display($record){
    // Override how the year is displayed in the UI.
    return $record->val('year').' A.D.';
}
</code>

==How to Define a Calculated Field==

In the delegate class you simply create a method with the following naming convention:
<code>
function field__fieldname(Dataface_Record $record);
</code>

where the return value is the value that the given record should have for the field ''filedname''.

E.g.

<code>
function field__year($record){
    $time = trtotime($record->strval('date'));
    if ( $time ){
        return date('Y', $time));
    } else {
        return '';
    }
}
</code>","calculated fields, field__fieldname",en,
init,140,"init() Delegate Class Method","== Synopsis ==

This method is called once, just after the table is loaded for the first time. It allows you to specify initialization details, such as [[setSecurityFilters|security filters]].

Note that it takes a single parameter: a Dataface_Table object of the table that is being initialized. 

== Example ==
<code>
function init(&$table){

   ....
}
</code>",,en,
Grafted_fields,158,"Grafted fields","==Grafted Fields==

===Introduction===
When there are numerous tables, it is difficult for the user to see get an information that will help one to enter the right data in the right field. So instead of navigating in the relative tables and lose some time, it is more convenient to add a grafted field from that relative table in the table. To be able to sort a column by the content displayed when this content is extracted form a relative table, a grafted field is necessary because the real content is just an id, not the most convenient to sort in human-readable way.
===Procedure===
Two ways to add a grafted filed
* The first one is to add a __sql__ statement at the beginning of fields.ini, including the grafted field through a join.
<code>__sql__ = ""select p.*, d.total from programmation p left join dev d on p.id_programmation=d.id_programmation"" </code>
* The second one is to create the function __sql__ in the delegate class
<code>function __sql__(){
return ""select p.*, d.total from programmation p left join dev d on p.id_programmation=d.id_programmation"";
}
</code>
===Sorting order based on relationship===
The solution is to hide the field with the id and to add the grafted field with the name in the fields.ini
<code>[name_programmation]
order=10

[id_programmation]
visibility:list=hidden
</code>

===Debugging===
A couple of things to check for:
*1. If you have set blanket default permissions for your fields using the __field__permissions() method you could be disallowing access to the field.
*2. If you have set default field visibility in the fields.ini file via the [__global__] section....
*3. Check to make sure that your __sql__ directive is at the beginning of the file and that it is __sql__ and not _sql_
*4. Try to enter an obviously invalid SQL query for the __sql__ directive to see if you get an error (to confirm that it is picking up the __sql__ directive at all).
","grafted fields, grafted, sorting columns, sort, relative records, relative tables",en,
Clean_the_html_for_the_export,178,"Clean the HTML to export data","==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:

<code> 
    __sql__ = ""select t.*, null as stripped_field from mytable t""
    [original_field]
       widget:type=htmlarea
       visibility:csv=hidden

    [stripped_field]
        visibility:csv = visible
        visibility:list=hidden
        visibility:browse=hidden
        visibility:find=hidden

</code> 


Then in the delegate class:


<code> 
    function stripped_field__display($record){
        return html_entity_decode(strip_tags($record->val('original_field')), ENT_QUOTES, 'UTF-8');
    }
</code> ",,en,
Cached_permissions,179,"Cached Permissions","==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 :
<code>
class tables_mytable {

    private $cachedPerms = null;
    private function _getCachedPerms($param1, $param2, ..., $paramN){
        if ( !isset($this->cachedPerms) ) {
            $this->cachedPerms = array();
            // do some stuff
            $res = mysql_query(""select * from foo where bar=1 and param2='"".addslashes($param2).""'"");
            while ( $row = mysql_fetch_assoc($res) )  $this->cachedPerms[$row['fooid']] = $row;
        }
        return $this->cachedPerms;
    }

    function getPermissions($record){
        // do some stuff
        $perms = $this->getCachedPerms($param1, $param2, ..., $paramN);
        return $perms;
    }
}</code>
Here, getPermissions() will run a db query on its first request, but subsequent requests will just load the cached value.","permissions, cache, quick, query",en,
test_page_34,177,"Hello World","Hello world",,en,
viewable_editable_fields,180,"How to make a field editable for some users and only viewable for some other users","If we want only some users to edit a field and some other users only to view that field, then we need to define a '''fieldX__permissions()''' method for that field which gives desired permissions for specific users.

One solution is as below.

==permissions.ini==
<code>
[Field Viewer]
view=1
edit=0
new=0

[Field Editor extends Field Viewer]
new=1
edit=1
</code>

==TableX.php (Delegate class of TableX)==
<code>
function fieldX__permissions(&$record) {
	$user=&Dataface_AuthenticationTool::getInstance()->getLoggedInUser();
	
	if($user) {
		if($user->val('usernameField')==""UserX"")
			$role='Field Viewer';
		else if($user->val('usernameField')==""UserY"")
			$role='Field Editor';				

			return Dataface_PermissionsTool::getRolePermissions($role);
	}
		
	return Dataface_PermissionsTool::NO_ACCESS();
}
</code>",,en,
column:legend,182,,,,en,
advmultiselect,183,,,,en,
loginFailed,184,"loginFailed() Application Delegate Trigger","[[toc]]

The loginFailed() method of the Application Delegate class is executed after a failed login attempt.

'''Available since 2.0.1'''

==Example==

<code>
function loginFailed($username, $userIp, $time){
    error_log(""Failed login for username: $username at IP $userIp at time $time"");
}
</code>
","login permissions failed password",en,
