<?xml version="1.0"?>
<record><wiki id="wiki?page_id=72">
	<page_name>GettingStarted:Why_Use_Xataface</page_name>
	<page_id>72</page_id>
	<page_title>Why Use Xataface</page_title>
	<content>==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 &apos;yes&apos;, then you probably won&apos;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&apos; 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&apos;s tool - not a secretary&apos;s tool, so it can be difficult to learn at first. The best reason NOT to install Dreamweaver on the Program Assistant&apos;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&apos;s include Plone, Drupal, and Xoops. Suppose we want to develop the Faculty of Widgetry website using one of these CMS&apos;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&apos;s allow you to develop custom content-types using the underlying programming language and an API (Application Programming Interface). Some API&apos;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&apos;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&apos;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&apos;s). Choose your CMS carefully.

====Solution 3: Use an existing Application====

OK, OK, let&apos;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&apos;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&apos;re lucky, maybe you can find an application that does exactly what you need (but frankly, I&apos;ve never been that lucky). If you find one, maybe it&apos;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:

&apos;&apos;&apos;Programs&apos;&apos;&apos;: 

* Fields:
** ProgramID : int
** ProgramName : varchar
** ProgramDescription: text
** AdmissionDeadline: date
** Outline_HTML : text
** Outline_PDF : blob


&apos;&apos;&apos;Courses&apos;&apos;&apos;:
* Fields:
** CourseID : int
** CourseSubject : varchar
** CourseTitle : varchar
** CourseNumber : int
** ProgramID : int
** CourseDescription : text
** Outline_HTML : text
** Outline_PDF : blob


Now it&apos;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).

&apos;&apos;&apos;Question&apos;&apos;&apos;: How will the Program Assistants update the information in the database?

&apos;&apos;&apos;Answer&apos;&apos;&apos;: OK, let&apos;s assume that you&apos;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&apos;t really its own solution. It is more like &quot;Solution 4 Part II&quot;, 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.</content>
	<keywords>introduction motivation why</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=71">
	<page_name>GettingStarted:Introduction</page_name>
	<page_id>71</page_id>
	<page_title>Introduction</page_title>
	<content>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:

&apos;&apos;&apos;Framework&apos;&apos;&apos; - 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)

&apos;&apos;&apos;Data-driven design&apos;&apos;&apos;- Designing an application around the data that it will store.

Xataface is a &apos;&apos;Framework&apos;&apos; 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 &apos;&apos;data-driven design&apos;&apos; 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] &gt;= 4.3
* [http://mysql.com MySQL] &gt;= 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.</content>
	<keywords>introduction requirements getting started</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=103">
	<page_name>Customizing_Theme_Based_on_IP_Address</page_name>
	<page_id>103</page_id>
	<page_title>Customizing Theme Based on IP Address</page_title>
	<content>This article deals with the following topics:

# Using [[field__pullValue]]/[[field__pushValue]] methods to customize how a field is edited and stored in the database.
# Using [[beforeHandleRequest]] to modify the application settings based on the user&apos;s IP address
# Storing ranges of IP addresses in the database.

Last week I set up a site that needed to have slightly different behavior depending on the IP address of the remote user.  E.g.  If a user is connecting from an IP address between 192.168.0.0 to 192.168.0.255 we would use a different theme than if they were connecting from a different block.  In addition to different themes, we also to use different types of authentication depending on which IP block the user is visiting from.

This requirement is actually common for systems that are syndicated by different organizations and should behave slightly differently depending on which organization the user belongs to (assuming they are connecting from that organization&apos;s network).

To implement this behavior we need to solve one issue.

&apos;&apos;&apos;How do we store a range of IP addresses in the database so that they can be queried easily to match if the user&apos;s IP address falls in that range.&apos;&apos;&apos;
	
It turns out that this is quite easy to do, since IP addresses are actually just a 4 digit number (base 256).  So we can easily convert this number to base 10 and store it as a regular unsigned integer in the database.  In addition, both PHP and MySQL provide functions to convert from an IP address to an integer and back.

The PHP functions are called [http://ca3.php.net/long2ip long2ip] and [http://ca3.php.net/ip2long ip2long] respectively.

So we have stored a start IP address and an end IP address as integers, we could simply query the database to see if a given IP address falls in that range as follows:

&lt;code&gt;
$intIP = ip2long($_SERVER[&apos;REMOTE_ADDR&apos;]);
$sql = sprintf(&apos;select * from ip_blocks where start_ip&lt;=%u and end_ip&gt;=%u&apos;, $intIP, $intIP);
... etc....
&lt;/code&gt;

&apos;&apos;&apos;It is important to note that you need to use the sprintf() function for converting $intIP into a string because PHP will convert it to an integer which could overflow if you leave it to do a default conversion.&apos;&apos;&apos;
	
For the above query, we assuming a table with a definition like:

&lt;code&gt;
create table ip_blocks (
    ip_block_id int(11) not null primary key,
    start_ip unsigned int(11) not null
    end_ip unsigned int(11),
    key (start_ip),
    key (end_ip)
)
&lt;/code&gt;
	
Now if we attach some information to the IP block, like the theme that should be used, we can check the user IP address against the available IP blocks at the beginning of each request to set the theme for that request.  We will use the [[beforeHandleRequest]] method of the [[Application Delegate Class]] to house this because it allows us to set things like the theme or change the user&apos;s action.

e.g.

&lt;code&gt;
class conf_ApplicationDelegate {
	function beforeHandleRequest(){
		$app = Dataface_Application::getInstance();
		
		// Get a reference to the current query so we can
		// alter it if necessary.
		$query =&amp; $app-&gt;getQuery();
		
		
		// Get the user&apos;s IP address and covert it to a long int.
		$intIP = ip2long($_SERVER[&apos;REMOTE_ADDR&apos;]);
		$sql = sprintf(&apos;select `theme` from ip_blocks where start_ip&lt;=%u and end_ip&gt;=%u&apos;, $intIP, $intIP);
		
		$res = mysql_query($sql, df_db());
		if ( !$res ) throw new Exception(mysql_error(df_db()));
		
		$row = mysql_fetch_row($res);
		
		// If we didn&apos;t find any valid IP ranges, let&apos;s redirect the
		// user to a different action to let them know that
		// they&apos;re not welcome here.
		if ( !$row ){
			$query[&apos;-action&apos;] = &apos;not_welcome&apos;;
				// This assumes that we have defined an action
				// called &quot;not_welcome&quot;
				
			return;
		}
		
		$theme = $row[0];
		$themePath = &apos;themes/&apos;.basename($theme);
		// Check that the theme exists.
		if ( $theme and file_exists($themePath) ){
			df_register_skin($theme, $themePath);
		}
	}
}
&lt;/code&gt;

The above snippet makes use of the [[df_register_skin]] method that registers a theme to be used dynamically.  The first parameter is the theme name, and the second parameter is the path to the theme.


This code works great if we already have IP addresses stored properly as integers in our database, but how do we make it so users can work with the IP addresses as IP addresses and not integers?  We need to be able to transform from integer to IP address to display in the edit record form, and then convert the resulting IP address back to an integer for storage in the database.  Xataface provides two delegate class methods precisely for this purpose:

# [[field__pullValue]] - Transforms a value as stored in the database to a format that is preferred in the edit form.
# [[field__pushValue]] - Transforms a value entered into the edit form into a format that is preferred by the database.

So, in our delegate class we would have:

&lt;code&gt;
&lt;?php
class tables_ip_blocks {

	/**
	 * @param Dataface_Record $record The record we are pushing the value
	 *		into
	 * @param HTML_QuickForm_element $el The QuickForm widget that we are 
	 *      retrieving the value from.
	 */
	function start_ip__pushValue($record, $el){
		$val = ip2long($el-&gt;getValue());
		if ( $val !== false ){
			return sprintf(&apos;%u&apos;, $val );
		}
		return null;
	}
	
	function start_ip__pullValue($record, $el){
		$val = $record-&gt;val(&apos;start_ip&apos;);
		if ( $val )
			return long2ip($val);
		return $val;
	}
	
	function end_ip__pushValue($record, $el){
		$val = ip2long($el-&gt;getValue());
		if ( $val !== false ){
			return sprintf(&apos;%u&apos;, $val );
		}
		return null;
	}
	
	function end_ip__pullValue($record, $el){
		$val = $record-&gt;val(&apos;end_ip&apos;);
		if ($val){
			return long2ip($val);
		}
		return $val;
	}
	
	
}
&lt;/code&gt;

The [[field__pullValue]] and [[field__pushValue]] method should be inverses of each other.

&apos;&apos;&apos;Note that support for [[field__pullValue]] and [[field__pushValue]] are supported by Xataface since version 0.6, however support for them with the grid widget was not added until Xataface version 1.3.&apos;&apos;&apos;
	

Now, on the edit form, users can enter and edit IP addresses in the normal format, but they will be converted to unsigned integers for storage in the database.

There is only one thing remaining, though.  In the list view still shows the integer version of the IP addresses. We want them to show them as regular IP addresses.  So we add [[field__display]] methods to our delegate class:

&lt;code&gt;
function start_ip__display($record){
	$val = $record-&gt;val(&apos;start_ip&apos;);
	if ( $val )
		return long2ip($val);
	return $val;
}

function end_ip__display($record){
	$val = $record-&gt;val(&apos;end_ip&apos;);
	if ($val){
		return long2ip($val);
	}
	return $val;
}
&lt;/code&gt;

==References==

* [http://xataface.com/documentation/how-to/how-to-define-custom-serialization-for-fields How to define custom serialization for fields]
</content>
	<keywords>ip address, pullValue, pushValue, beforeHandleRequest</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=93">
	<page_name>Authenticating_Against_the_Joomla!_Users_Table</page_name>
	<page_id>93</page_id>
	<page_title></page_title>
	<content>Xataface is able to use the joomla users table to authenticate against so that, you can allow your users to log into your Xataface application using the same credentials as they use to access your joomla website. Achieving this level of integration requires 2 simple steps :
1 - Set up the [_auth] section of your conf.ini file to reference the joomla users table and the correct username and password columns.
2 - Create a delegate class for the joomla users table to be able to decrypt the password set in the table.
==Configure the conf.ini file==
Joomla users table is named jos_users. So you have to declare this table in the conf.ini file.
&lt;code&gt;[_auth]
users_table = jos_users
username_column = username
password_column = password&lt;/code&gt;
Note that username_column and password_column are very simple...
==Create a delegate class for your users table==
Now we have to create a delegate class for the users table to decrypt the passwords set in joomla.
Joomla uses a custom md5 encryption.
===Joomla encryption===
When a user is setting a password in joomla, the system does several things :
1 - generate a random key containing alphanumeric characters
example : 
&lt;code&gt;8NdiRqLRKLHaNwudJ3InJknsew9sc7pL&lt;/code&gt;
2 - concate the clear entered password with the random key
example : 
&lt;code&gt;password8NdiRqLRKLHaNwudJ3InJknsew9sc7pL&lt;/code&gt;
3 - doing a md5 encryption on the result string
example : 
&lt;code&gt;md5(password8NdiRqLRKLHaNwudJ3InJknsew9sc7pL = f2b1fb3996442db549c1ed1a1eebbfe1&lt;/code&gt;
4 - concate the md5 string with the random key separated by &quot;:&quot;
example :
&lt;code&gt;f2b1fb3996442db549c1ed1a1eebbfe1:8NdiRqLRKLHaNwudJ3InJknsew9sc7pL&lt;/code&gt;
So it&apos;s a great encryption but xataface doesn&apos;t know how to do that.
Here is the utility of the delegate class. We will define a function inside which could compare the entered password in xataface with the joomla stored password.
===Creating the delegate class===
1 - Add a jos_users directory in your directory table
2 - Create a jos_users.php file inside this new directory
===Creating the decrypt password function===
Before posting this code, I would like to thank fantomasdm who created this function.
So here is the code of the function to paste directly in the jos_users delegate class :
&lt;code&gt;&lt;?
class tables_jos_users {
	
function password__serialize($password){

   $app =&amp; Dataface_Application::getInstance(); 
   $query = &quot;SELECT id, gid, block, password, usertype FROM jos_users where username=&apos;&quot;.$_POST[&apos;UserName&apos;].&quot;&apos;&quot;;
   $result = mysql_query($query,$app-&gt;db()) or die(&quot;Query failed&quot; . mysql_error() );

   $line = mysql_fetch_array($result, MYSQL_ASSOC);
   mysql_free_result($result);

   $arraypass=explode(&quot;:&quot;, $linea[&apos;password&apos;]);
   $key=$arraypass[1];
   
   $ret = md5(trim($password).$key).&quot;:&quot;.$key;
   return $ret;
} 
}
?&gt;&lt;/code&gt;
Save your file and test the result.
Enjoy ! ;-)</content>
	<keywords>joomla authentication md5</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=83">
	<page_name>Key</page_name>
	<page_id>83</page_id>
	<page_title>fields.ini Directive: Key</page_title>
	<content>The &apos;&apos;&apos;Key&apos;&apos;&apos; 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:
&lt;code&gt;
create view books_2000 as
select * from books where year=&apos;2000&apos;
&lt;/code&gt;

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:

&lt;code&gt;
[book_id]
    Key=PRI
&lt;/code&gt;

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:
&lt;code&gt;
[author_id]
    Key=PRI

[book_index]
    Key=PRI
&lt;/code&gt;

Links:
* [http://xataface.com/forum/viewtopic.php?f=4&amp;t=6723 Lookup widget on view with compound primary key]

Return to [[fields.ini file]]</content>
	<keywords>Key, Views, MySQL Views, Create View, PRI, Primary Keys</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=65">
	<page_name>LDAP_or_Active_Directory</page_name>
	<page_id>65</page_id>
	<page_title>How to authenticate users with LDAP or Active Directory</page_title>
	<content>[[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 :

&lt;code&gt;[_auth]
auth_type=ldap
users_table = xata_users
username_column = id
	ldap_host = &quot;xxx.xxx.xxx.xxx&quot;
	ldap_port = &quot;389&quot;
	ldap_base = &quot;OU=blabla,DC=blablabla&quot;&lt;/code&gt;

Here in the table users, you need the login but the password can be just &apos;&apos;PASS&apos;&apos;, 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</content>
	<keywords>LDAP,Active Directory,Authentication</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=184">
	<page_name>loginFailed</page_name>
	<page_id>184</page_id>
	<page_title>loginFailed() Application Delegate Trigger</page_title>
	<content>[[toc]]

The loginFailed() method of the Application Delegate class is executed after a failed login attempt.

&apos;&apos;&apos;Available since 2.0.1&apos;&apos;&apos;

==Example==

&lt;code&gt;
function loginFailed($username, $userIp, $time){
    error_log(&quot;Failed login for username: $username at IP $userIp at time $time&quot;);
}
&lt;/code&gt;
</content>
	<keywords>login permissions failed password</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=61">
	<page_name>lookup</page_name>
	<page_id>61</page_id>
	<page_title>The Lookup Widget</page_title>
	<content>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&apos;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 &apos;&apos;&apos;lookup&apos;&apos;.  I.e.
&lt;code&gt;
[fieldname]
    widget:type=lookup
    widget:table=mytable
&lt;/code&gt;

&apos;&apos;&apos;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.&apos;&apos;&apos;

===Required Directives===

The following [[fields.ini file]] directives are required to accompany the field definition if a lookup widget is used:

{| class=&quot;listing listing2&quot;
|-
! 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=&quot;listing listing2&quot;
|-
! 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.&lt;code&gt;widget:filters:-limit=100&lt;/code&gt; to show 100 records at a time.
| 1.0
|-
| widget:filters:-sort
| Specifies the columns to sort the results on. E.g. &lt;code&gt;widget:filters:-sort=category_name asc, year desc&lt;/code&gt;
| 1.0
|-
| widget:filters:*
| Any valid Xataface directive can be used to filter the results by specifying widget:filters:param  (where &quot;param&quot; is a valid Xataface GET parameter, which could include a column name to filter results on, or other filter directives). &lt;code&gt;widget:filters:country=Canada&lt;/code&gt; 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. &lt;code&gt;widget:filters:country_id=&quot;$country_id&quot;&lt;/code&gt; would show only results with records having country_id matching the value of the &apos;country_id&apos; 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:

&lt;pre&gt;
[appointee]
    widget:type=lookup
    widget:table=contacts
&lt;/pre&gt;

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&apos;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(&amp;$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&amp;t=6723 Lookup widget on view with compound primary key]</content>
	<keywords>lookup widget, widget:filters, widget:-filters:limit, widget:table</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=112">
	<page_name>Module_Developers_Guide</page_name>
	<page_id>112</page_id>
	<page_title>Module Developers Guide</page_title>
	<content>[[toc]]

==Why Write a Xataface Module?==

Xataface modules are components that can be used to extend Xataface&apos;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&apos;s modules directory (i.e. DATAFACE_SITE_PATH/modules).

==Your first module==

For our first module, we&apos;re going to create a simple module that adds &quot;hello world&quot; at the beginning of every page.

===Step 1: Create the Module Class===

In your modules directory, create a directory called &quot;Hello&quot;.  And in this directory, create a file named &quot;Hello.php&quot;, with the following contents:
&lt;code&gt;
&lt;?php
class modules_Hello  {
}
&lt;/code&gt;
(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 &quot;hello world&quot; 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 &apos;&apos;block__before_body&apos;&apos; method in your module (just as we would if we were trying to fill this slot from the [[Application Delegate Class]].

&lt;code&gt;
&lt;?php
class modules_Hello  {
    function block__before_body(){
        echo &quot;hello world&quot;;
        return true;
    }
}
&lt;/code&gt;

===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]]:

&lt;code&gt;
[_modules]
modules_Hello=modules/Hello.php
&lt;/code&gt;

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 &quot;hello world&quot; 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&apos;s now extends that to include a custom action that displays Hello World on its own page.

Complete the following steps:

# Add an &apos;&apos;actions&apos;&apos; directory inside our new module directory.  i.e. modules/Hello/actions
# Add a file named hello.php inside the &apos;&apos;actions&apos;&apos; directory with the following contents:&lt;code&gt;
&lt;?php
class actions_hello {
    function handle($params){
        echo &quot;Hello World&quot;;
    }
}
&lt;/code&gt;
# Go to index.php?-action=hello To see the results of your action.  It should say &quot;Hello World&quot; on a blank page.

From here on you can improve this action just as you would if you defined the action inside the application&apos;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 &quot;hello&quot; permission for our action===

Perhaps we want to create a special permission for our action so that regular users won&apos;t have access to this action unless they are specifically granted this permission.  Let&apos;s create a &quot;hello&quot; permission with which to limit access to our action.

# Create a file named &quot;permissions.ini&quot; inside your modules/Hello directory with the following contents:&lt;code&gt;
hello = Permission to access the hello action
&lt;/code&gt;

Now if you try to access your action (and you haven&apos;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&apos;s assigned roles or return it as part of the list of authorized permissions in the getPermissions() method.

===Granting the &quot;hello&quot; permission to the &quot;READ ONLY&quot; role===

If we want the default READ ONLY role to have access to the &quot;hello&quot; permission we can actually modify the READ ONLY role inside the [[permissions.ini file]] that we created inside the Hello module:

&lt;code&gt;
hello = Permission to access hello action

[READ ONLY extends READ ONLY]
    hello=1
&lt;/code&gt;


==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&apos;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 &apos;&apos;templates&apos;&apos; directory inside your module directory for use by your module&apos;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&apos;s modify our hello action to use a template that we are going to store and distribute with our module.

# Create a directory named &quot;templates&quot; in the modules/Hello directory.
# Create a file named &quot;hello.html&quot; inside the templates directory with the following contents:&lt;code&gt;
{use_macro file=&quot;Dataface_Main_Template.html&quot;}
    {fill_slot name=&quot;main_section&quot;}
    	Hello World
    {/fill_slot}
{/use_macro}
&lt;/code&gt;  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:&lt;code&gt;&lt;?php
class actions_hello {
    function handle($params){
        df_register_skin(&apos;hello theme&apos;, dirname(__FILE__).&apos;../templates&apos;);
        df_display(array(), &apos;hello.html&apos;);
    }
}
&lt;/code&gt;  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&apos;s Look and Feel with Templates] - A tutorial on how to use Xataface&apos;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&apos;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.</content>
	<keywords>modules</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=30">
	<page_name>modules</page_name>
	<page_id>30</page_id>
	<page_title>Xataface Modules</page_title>
	<content>[[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]].</content>
	<keywords>modules, captcha</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=45">
	<page_name>_output_cache</page_name>
	<page_id>45</page_id>
	<page_title>The Xataface Output Cache</page_title>
	<content>&lt;nowiki&gt;&lt;div class=&quot;portalMessage&quot;&gt;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.&lt;/div&gt;&lt;/nowiki&gt;

[[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&apos;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 &apos;&apos;__output_cache&apos;&apos; 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&apos;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 &apos;&apos;out of date&apos;&apos; 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 &apos;&apos;__output_cache&apos;&apos; table.

===How do I enable the Cache?===

Add the following to your [[conf.ini file]]:

&lt;code&gt;
[_output_cache]
    enabled=1
&lt;/code&gt;

===How do I disable the Cache?===

Simply comment out or remove the &apos;&apos;[_output_cache]&apos;&apos; section of your [[conf.ini file]].  E.g.
&lt;code&gt;
;[_output_cache]
;   enabled=1
&lt;/code&gt;

===Configuration Options===

The following directives can be added to the &apos;&apos;[_output_cache]&apos;&apos; section of your [[conf.ini file]] to customize how your output cache works.

{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Version
|-
| lifeTime
| Number of seconds before cached page is considered &apos;&apos;out of date&apos;&apos;.
| 0.7
|-
| tableName
| The name of the table to store the cached pages.  Default &apos;__output_cache&apos;.
| 0.7
|-
| ignoredTables
| A comma-delimited list of tables that don&apos;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
|}</content>
	<keywords>output cache</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=179">
	<page_name>Cached_permissions</page_name>
	<page_id>179</page_id>
	<page_title>Cached Permissions</page_title>
	<content>==Cached Permissions==

===Introduction===
When you insert a SQL query in your getPermissions function, this will slow down the app dramatically because this function is called by each query. To resolve this problem, it is better to use cached permissions in your /conf/ApplicationDelegate.php or table/table.php.

===Procedure===
Here is an example :
&lt;code&gt;
class tables_mytable {

    private $cachedPerms = null;
    private function _getCachedPerms($param1, $param2, ..., $paramN){
        if ( !isset($this-&gt;cachedPerms) ) {
            $this-&gt;cachedPerms = array();
            // do some stuff
            $res = mysql_query(&quot;select * from foo where bar=1 and param2=&apos;&quot;.addslashes($param2).&quot;&apos;&quot;);
            while ( $row = mysql_fetch_assoc($res) )  $this-&gt;cachedPerms[$row[&apos;fooid&apos;]] = $row;
        }
        return $this-&gt;cachedPerms;
    }

    function getPermissions($record){
        // do some stuff
        $perms = $this-&gt;getCachedPerms($param1, $param2, ..., $paramN);
        return $perms;
    }
}&lt;/code&gt;
Here, getPermissions() will run a db query on its first request, but subsequent requests will just load the cached value.</content>
	<keywords>permissions, cache, quick, query</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=26">
	<page_name>permissions.ini_file</page_name>
	<page_id>26</page_id>
	<page_title>permissions.ini_file</page_title>
	<content>==The permissions.ini File==

[[toc]]

The permissions.ini file stores custom permissions and roles that can be used by an application.  It is an optional file that should be placed in the application root directory (i.e. the same directory where your conf.ini, and index.php files are located).

The permissions.ini file allows you to define two things:

# Permissions
# Roles (i.e. sets of permissions).

Permissions and roles are used throughout Xataface to limit access to actions, records, fields, and relationships.  For example, each action in your application can specify a permission that is necessary to perform the action.  Your delegate classes may include getPermissions() methods to define what permissions a user gets when interacting with different records.  This file (permissions.ini) simply defines the permissions that can be used by your application.  It doesn&apos;t actually assign those permissions.  Assigning permissions is the job of the getPermissions() (or getRoles()) method.

===Defining Permissions===

Permissions are defined by standalone properties in the beginning of the permissions.ini file.  For example, if you were desiging a proof-reading application, you might need permissions for &quot;submit_for_proof&quot;, or &quot;approve_text&quot; to correspond with the submitting a document to be proof-read, and approving a document&apos;s proof.  In this case we would have the following at the beginning of our permissions.ini file:

&lt;code&gt;
submit_for_proof = Submit a document to be proofread
approve_text = &quot;Approve this document&apos;s proof&quot;
&lt;/code&gt;

The left side of the equals sign is the name of the permission.  The right side contains a human readable description of the permission and what it is for.

===Limiting Access to Actions based on Permissions===

At this point these permissions don&apos;t do anything.  In order to be useful we need reference these permissions from an action or a section.  For example, let&apos;s create an action called &quot;submit_for_proof&quot; which displays a form for a user to submit a document record to be proofread.

Our actions.ini file entry might look something like:

&lt;code&gt;
[submit_for_proof]
    url=&quot;{$this-&gt;url(&apos;-action=submit_for_proof&apos;)}&quot;
    label=&quot;Submit document for proof&quot;
    category=record_actions
    permission=submit_for_proof
    template=submit_for_proof.html
&lt;/code&gt;

And for completeness, since this make-believe action specifies th &quot;submit_for_proof.html&quot; template, we&apos;ll create the &quot;submit_for_proof.html&quot; template in the templates directory:

&lt;code&gt;
&lt;html&gt;&lt;body&gt;You have permission to perform this action.&lt;/body&gt;&lt;/html&gt;
&lt;/code&gt;

===Defining Who Get&apos;s Which Permissions===

Finally, in order to benefit from permissions, your application has to decide that it is going to use permissions (unless you define a getPermissions() method, users are granted ALL permissions by default.  Hence if you try to access our submit_for_proof action, we&apos;ll see it without any problem.  Regardless of who we are.  So let&apos;s create a simple, but restrictive getPermissions() method in our application delegate class:

&lt;code&gt;
&lt;?php
class conf_ApplicationDelegate {
    function getPermissions(&amp;$record){
        return Dataface_PermissionsTool::READ_ONLY();
    }
}
&lt;/code&gt;

Now if we try to access our submit_for_proof action it will give us a &quot;Permission Denied&quot; message, because we are only granted READ ONLY permissions (which is a role that includes the view permission and some others - but not our custom &quot;submit_for_proof&quot; permission.

Now we&apos;ll make a small modification to our getPermissions() method to provide us with our submit_for_proof permission:

&lt;code&gt;
&lt;?php
class conf_ApplicationDelegate {
    function getPermissions(&amp;$record){
        $perms =  Dataface_PermissionsTool::READ_ONLY();
        $perms[&apos;submit_for_proof&apos;] = 1;
        return $perms;
    }
}
&lt;/code&gt;

Now if we try to access our submit_for_proof action, it will show us our template with no error messages (hopefully).


===Roles===

Roles are sets of permissions.  They are defined in the permissions.ini file as sections with lists of included permissions.  It might be handy to create roles such as EDITOR or MANAGER which contain sets of permissions that are meant to be assigned to users of those types.  For example an EDITOR may have the view and edit permissions, but not the delete permission.  A MANAGER might have the view, edit, and delete permissions.  You can define these two roles in the permissions.ini file as follows:

&lt;code&gt;
[EDITOR]
    view=1
    edit=1

[MANAGER]
    view=1
    edit=1
    delete=1
&lt;/code&gt;

Then we could assign these roles to users using the Dataface_PermissionsTool::getRolePermissions() method:

&lt;code&gt;
function getPermissions(&amp;$record){
    $user =&amp; Dataface_AuthenticationTool::getInstance()-&gt;getLoggedInUser();
    if ( $user and $user-&gt;val(&apos;role&apos;) == &apos;EDITOR&apos; ){
        return Dataface_PermissionsTool::getRolePermissions(&apos;EDITOR&apos;);
    } else if ( $user and $user-&gt;val(&apos;role&apos;) == &apos;MANAGER&apos; ){
        return Dataface_PermissionsTool::getRolePermissions(&apos;MANAGER&apos;);
    }
    return Dataface_PermissionsTool::READ_ONLY();
}
 &lt;/code&gt;

Or equivalently we could use the getRoles() method of our delegate class instead of getPermissions():

&lt;code&gt;
function getRoles(&amp;$record){
    $user =&amp; Dataface_AuthenticationTool::getInstance()-&gt;getLoggedInUser();
    if ( $user and $user-&gt;val(&apos;role&apos;) == &apos;EDITOR&apos; ){
        return &apos;EDITOR&apos;;
    } else if ( $user and $user-&gt;val(&apos;role&apos;) == &apos;MANAGER&apos; ){
        return &apos;MANAGER&apos;
    }
    return &apos;READ ONLY&apos;;
}
&lt;/code&gt;

===Xataface Core Permissions &amp; Roles===

Xataface is distributed with its own permissions.ini file that defines some core permissions and roles.  You can look at this permissions.ini file (located in the Xataface directory) to see what the format should look like.  Any settings you place in your application&apos;s permissions.ini file will augment or override settings in Xataface&apos;s file.

Some core permissions include:


{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Version
|-
| view
| Permission to view a record or field.  This permission is required to access the view tab, and several other details tabs.
| 0.6
|-
| list
| Permission to access the list tab.
| 0.6
|-
| calendar
| Permission to access the calendar tab.
| 0.6
|-
| edit
| Permission to edit a record or field.  This also gives access to the edit tab.
| 0.6
|-
| new
| Permission to edit a record or field for the purpose of creating a new record.  This permission is required to access the new record form.
| 0.6
|-
| select_rows
| Permission to select rows in list view to perform actions on them.
| 0.6
|-
| post
| Permission to post a record using HTTP POST
| 0.6
|-
| copy
| Permission to copy a record.
| 0.6
|-
| update_set
| Permission to perform an update on a result set (i.e. access the update set action).
| 0.8
|-
| add new related record
| Permission to add a new record to a relationship.  See [[Relationship Permissions]]
| 0.6
|-
| add existing related record
| Permission to add an existing record to a relationship.  See [[Relationship Permissions]]
| 0.6
|-
| view related records
| Permission to view the records in a relationship. See [[Relationship Permissions]]
| 1.0
|-
| delete
| Permission to delete a record.
| 0.6
|-
| delete found
| Permission to access the delete found set action (to delete multiple records at a time).
| 0.6
|-
| show all
| Permission to access show all records action.
| 0.6
|-
| remove related record
| Permission to remove a record from a relationship.  See [[Relationship Permissions]]
| 0.6
|-
| delete related record
| Permission to delete a record in a relationship.  This is stronger than the remove related record permission in that it allows the user to delete the record from the database.  See [[Relationship permissions]]
| 0.6
|-
| find
| Permission to perform the find action.
| 0.6
|-
| import
| Permission to perform the import action (to import records into the database).
| 0.6
|-
| export_csv
| Permission to perform the Export CSV action (to export the result set in comma-separated-value format).
| 0.6
|-
| export_xml
| Permission to perform the Export XML action (to export the result set as XML).
| 0.8
|-
| translate
| Permission to translate a record into another language.  This permission provides access to the &quot;translate&quot; tab.
| 0.8
|-
| history
| Permission to view history information for a record (e.g. the history tab).  This requires that history be enabled.
| 0.8
|-
| edit_history
| Permission to edit history information such as undo/redo support for a record.
| 0.8
|-
| navigate
| Permission to navigate through records of a table.
| 0.6
|-
| reorder_related_records
| Permission to reorder the records of a relationship (this is different than just sorting).  It sets a default order for the records.  Requires the metafields:order directive to be set for the relationship.
| 0.6
|-
| ajax_save
| Permission to save a record through AJAX.
| 0.8
|-
| ajax_load
| Permission to load a record through AJAX.
| 0.8
|-
| ajax_form
| Permission to access the inline editing ajax form for a record.
| 0.8
|-
| find_list
| Permission to search current table.
| 0.6
|-
| find_multi_table
| Permission to perform a site-wide search.
| 0.8
|-
| register
| Permission to register for an account.
| 0.8
|-
| xml_view
| Permission to view a result set as xml.
| 0.8
|-
| view_xml
| View the XML for an individual record.
| 0.8
|-
| manage_output_cache
| Management permission to clear the output cache.
| 0.8
|-
| manage_migrate
| Permission to access the migration tool to migrate between versions.
| 0.8
|-
| manage
| Permission to access the management control panel.
| 0.8
|-
| manage_build_index
| Permission to rebuild the search index.
| 0.8
|-
| expandable
| Whether the record can be expanded in the left nav menu
| N/A
|}

Some core roles include:

{| class=&quot;listing listing2&quot;
|-
! Name
! Permissions Included
! Version
|-
| READ ONLY
| view, list, calendar, view xml, show all, find, navigate, ajax_load, find_list, find_multi_table, rss, export_csv, export_xml, and export_json
| 0.6
|-
| EDIT
| All permissions in READ ONLY, and edit, add new related record, add existing related record, add new record, remove related record, reorder_related_records, import, translate, new, ajax_save, ajax_form, history, edit_history, copy, update_set, and select_rows
| 0.6
|-
| DELETE
| All permissions in EDIT, and delete and delete found.
| 0.6
|-
| OWNER
| All permissions in DELETE except navigate, new, and delete found.
| 0.6
|-
| REVIEWER
| All permissions in READ ONLY, and edit and translate.
| 0.6
|-
| USER
| All permissions in READ ONLY, and add new related record.
| 0.6
|-
| ADMIN
| All permissions in DELETE and xml_view
| 0.6
|-
| MANAGER
| All permissions in ADMIN and manage, manage_output_cache, manage_migrate, manage_build_index, and install.
| 0.6
|}

===Extending and Overriding Roles===

The cleanest and easiest way to define a new role is to extend an existing role.  Xataface allows you to extend roles via the &apos;&apos;&apos;extends&apos;&apos;&apos; keyword.  For example, if you wanted to create a role &apos;&apos;&apos;TEST ROLE&apos;&apos;&apos; that contained all of the same permissions as the READ ONLY role, you could define it as follows in your application&apos;s permissions.ini file:

&lt;code&gt;
[TEST ROLE extends READ ONLY]
&lt;/code&gt;

If we wanted it to contain the same permissions as READ ONLY but to also allow the edit permission we would define it as:
&lt;code&gt;
[TEST ROLE extends READ ONLY]
    edit=1
&lt;/code&gt;

If we wanted to disallow the list permission, we would do something like:

&lt;code&gt;
[TEST ROLE extends READ ONLY]
    edit=1
    list=0
&lt;/code&gt;

===Overriding Existing Roles===

You can also redefine existing roles:

&lt;code&gt;
[READ ONLY extends READ ONLY]
    my_permission=1
&lt;/code&gt;

This is handy if you have added your own custom permissions that you feel should be included in a core role.

Note that there are some caveats regarding the order of how these roles are defined. Please refer to this forum post for more details: 
[http://www.xataface.com/forum/viewtopic.php?t=6187 Overriding Roles / Permissions]

==See Also==

* [[Relationship Permissions]]
* [[getPermissions]] - The getPermissionsMethod
* [[Delegate class methods]] - Delegate class methods.
* [http://xataface.com/documentation/tutorial/getting_started/permissions Getting started with Xataface permissions]</content>
	<keywords>permissions.ini, getPermissions, permissions</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=92">
	<page_name>Authenticating_Against_the_PHPBB_Users_table</page_name>
	<page_id>92</page_id>
	<page_title>Authenticating Against the PHPBB Users Table</page_title>
	<content>Return to [[authentication]]

[[toc]]

Xataface is able to use the PHPBB users table to authenticate against so that, you can allow your users to log into your Xataface application using the same credentials as they use to access your PHPBB message forum.  Achieving this level of integration requires 2 simple steps:

# Set up the [[_auth]] section of your [[conf.ini file]] to reference the PHPBB users table and the correct username and password columns.
# Specify the correct encryption on the password column.  This step will be different for different versions of PHPBB.

==PHPBB 2==

PHPBB version 2 and lower simply use MD5 encryption on the password column, which Xataface supports natively via the [[encryption]] directive of the [[fields.ini file]].  Therefore we can set up our Xataface application to authenticate against our PHPBB2 database (&apos;&apos;&apos;assuming that our PHPBB is set up in the same database as our Xataface app&apos;&apos;&apos;) by doing the following:

# Set up the [_auth] section of the [[conf.ini file]] as follows:&lt;code&gt;
[_auth]
users_table = phpbb_users
username_column = username
password_column = user_password
&lt;/code&gt;
# Set up the user_password field to use md5 encryption in the &apos;&apos;tables/phpbb_users/fields.ini&apos;&apos; file &lt;code&gt;
[user_password]
encryption=md5
&lt;/code&gt;

That&apos;s it!  Now you should be able to log into your Xataface application using the username/password from PHPBB.


==PHPBB 3==

PHPBB version 3 and higher uses a custom encryption function for the password column so it is a little more complicated (but not that much).  Step one (the [[conf.ini file]]) is the same as for PHPBB version 2 listed above.  The 2nd part, however, requires us to implement a custom serialization for the user_password field.  So the steps are below:

# Set up the [_auth] section of the [[conf.ini file]] as follows:&lt;code&gt;
[_auth]
users_table = phpbb_users
username_column = username
password_column = user_password
&lt;/code&gt;
# Implement the user_password__serialize() method in your phpbb_users delegate class (i.e. the &apos;&apos;tables/phpbb_users/phpbb_users.php&apos;&apos; file):&lt;code&gt;
&lt;?php
class tables_phpbb_users {
	

	function user_password__serialize($password){
		$itoa64 = &apos;./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz&apos;;
		$sql = &quot;select user_password from phpbb_users where username=&apos;&quot;.addslashes($_POST[&apos;UserName&apos;]).&quot;&apos;&quot;;
		$res = mysql_query($sql, df_db());
		if ( !$res ) throw new Exception(mysql_error(df_db()));
		$row = mysql_fetch_assoc($res);
		mysql_free_result($res);
		$hash = $this-&gt;_hash_crypt_private($password, $row[&apos;user_password&apos;], $itoa64);
		return $hash;
	}
	
	
	/**
	* The crypt function/replacement
	*/
	function _hash_crypt_private($password, $setting, &amp;$itoa64)
	{
		$output = &apos;*&apos;;
	
		// Check for correct hash
		if (substr($setting, 0, 3) != &apos;$H$&apos;)
		{
			return $output;
		}
	
		$count_log2 = strpos($itoa64, $setting[3]);
	
		if ($count_log2 &lt; 7 || $count_log2 &gt; 30)
		{
			return $output;
		}
	
		$count = 1 &lt;&lt; $count_log2;
		$salt = substr($setting, 4, 8);
	
		if (strlen($salt) != 8)
		{
			return $output;
		}
	
		/**
		* We&apos;re kind of forced to use MD5 here since it&apos;s the only
		* cryptographic primitive available in all versions of PHP
		* currently in use.  To implement our own low-level crypto
		* in PHP would result in much worse performance and
		* consequently in lower iteration counts and hashes that are
		* quicker to crack (by non-PHP code).
		*/
		if (PHP_VERSION &gt;= 5)
		{
			$hash = md5($salt . $password, true);
			do
			{
				$hash = md5($hash . $password, true);
			}
			while (--$count);
		}
		else
		{
			$hash = pack(&apos;H*&apos;, md5($salt . $password));
			do
			{
				$hash = pack(&apos;H*&apos;, md5($hash . $password));
			}
			while (--$count);
		}
	
		$output = substr($setting, 0, 12);
		$output .= $this-&gt;_hash_encode64($hash, 16, $itoa64);
	
		return $output;
	}
	
	/**
	* Encode hash
	*/
	function _hash_encode64($input, $count, &amp;$itoa64)
	{
		$output = &apos;&apos;;
		$i = 0;
	
		do
		{
			$value = ord($input[$i++]);
			$output .= $itoa64[$value &amp; 0x3f];
	
			if ($i &lt; $count)
			{
				$value |= ord($input[$i]) &lt;&lt; 8;
			}
	
			$output .= $itoa64[($value &gt;&gt; 6) &amp; 0x3f];
	
			if ($i++ &gt;= $count)
			{
				break;
			}
	
			if ($i &lt; $count)
			{
				$value |= ord($input[$i]) &lt;&lt; 16;
			}
	
			$output .= $itoa64[($value &gt;&gt; 12) &amp; 0x3f];
	
			if ($i++ &gt;= $count)
			{
				break;
			}
	
			$output .= $itoa64[($value &gt;&gt; 18) &amp; 0x3f];
		}
		while ($i &lt; $count);
	
		return $output;
	}

	

}
&lt;/code&gt;</content>
	<keywords>PHPBB, authentication, security, authentication modules</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=10">
	<page_name>preferences</page_name>
	<page_id>10</page_id>
	<page_title>preferences</page_title>
	<content>==Xataface Preferences==

[[toc]]

Xataface preferences can be defined in 3 ways:

# In the &apos;&apos;[_prefs]&apos;&apos; section of rhe [[conf.ini file]] for global static preferences.
# Implementing the [[getPreferences]] method in the [[Application Delegate Class]]
# In the [[__prefs__]] section of the fields.ini file for a table for static preferences on that table.  (Limited to only certain preferences).

===Example [_prefs] section===
In the conf.ini
&lt;code&gt;
[_prefs]
    hide_updated=1
    hide_posted_by=1
&lt;/code&gt;

===Example [[getPreferences]] method===
In the [[Application Delegate Class]]:
&lt;code&gt;
function getPreferences(){
    return array(&apos;hide_update&apos;=&gt;1, &apos;hide_posted_by&apos;=&gt;1);

}
&lt;/code&gt;

===Available Preferences===

{| class=&quot;listing listing2&quot;
! Name
! Description
! Default
! Version
|-
| show_result_stats
| Show the result statistics (e.g. found x of y records in table z)
| 1
| 0.6
|-
| show_jump_menu
| Show he drop-down menu that allows you to &quot;jump&quot; to any record in the found set.
| 1
| 0.6
|-
| show_result_controller
| Show Next, previous, page number .. links...
| 1
| 0.6
|-
| show_table_tabs
| Show  Details, List, Find, etc... tabs.
| 1
| 0.6
|-
| show_actions_menu
| Show New record, Show all, delete, etc..
| 1
| 0.6
|-
| show_logo
| Show logo at top of app
| 1
| 0.6
|-
| show_tables_menu
| Show the tabs to select a table.
| 1
| 0.6
|-
| show_search
| Show search field in upper right.
| 1
| 0.6
|-
| show_record_actions
| Show actions related to particular record
| 1
| 0.6
|-
| show_bread_crumbs
| Show bread crumbs at top of page to show where you are.
| 1
| 0.6
|-
| show_record_tabs
| View, Edit, Translate, History, etc...
| 1
| 0.6
|-
| show_record_tree
| Show tree to navigate the relationships of this record.
| 1
| 0.6
|-
| list_view_scroll_horizontal
| Whether to scroll list horizontal if it exceeds page width
| 1
| 0.6
|-
| list_view_scroll_vertical
| Whether to scroll list vertical if it exceeds page height.
| 1
| 0.6
|-
| hide_posted_by
| Whether to hide the &apos;&apos;posted by&apos;&apos; text in glance lists (e.g. in the view tab, the related records are shown in the left column.  This hides the &apos;&apos;posted by&apos;&apos; text next to each related record.
| 0
| 1.0b4
|-
| hide_updated
| Whether to hide the &apos;&apos;updated&apos;&apos; text in the glance lists (e.g. in the view tab, the related records are shown in the left column.  This hides the &apos;&apos;updated&apos;&apos; text next to each related record.
| 0
| 1.0b4
|-
| SummaryList_logo_width
| The width of the logo to be used as the preview image in summary lists.
| null
| 0.7
|-
| SummaryList_hideSort
| Hides the sort control for a summary list (the box that allows users to sort by column).
| 0
| 0.7
|-
| hide_user_status
| Hides the user&apos;s status (e.g. &quot;You are logged in as ...&quot;
| 0
| 0.7
|-
| hide_personal_tools
| Hides the personal tool links in upper right.  This includes likes such as &quot;Control Panel&quot; and &quot;My Profile&quot;
| 0
| 0.7
|-
| hide_resultlist_controller
| Hides the controller for a result list (E.g. next/back/results per page etc...).
| 0
| 0.7
|-
| hide_related_sections
| Hides the sections of the view tab that show the related records.  These are the sortable section boxes.  Not the related tabs.
| 0
| 1.3
|-
| hide_record_search
| Hides the record search form that appears in the view tab.  Not to be confused with the find tab.
| 0
| 1.3
|-
| show_resultlist_controller_only_when_needed
| Sets the resultlist controller (e.g. back/next/results per page/etc...) to only show up if paging is required (i.e. if there are more records than can be shown on one page (according to the &apos;-limit&apos; parameter).
| 0
| 1.0
|-
| hide_record_view_logo
| Hides the logo for a record that appears in the upper left of the view tab for each record.
| 0
| 0.7
|-
| horizontal_tables_menu
| Whether to force the tables menu to appear as tabs along the top of the page (alternative is as a menu on the left). If there are 10 or fewer allowed tables, then the default is 1, otherwise the default is set to 0.
| 1
| 0.6
|-
| hide_result_filters
| In list view, setting this value to 1 will cause the column filters to be hidden (the select lists to filter the results).
| 0
| 0.7
|-
| disable_select_rows
| A value of 1 causes the checkboxes in each row of the list view to be hidden.
| 0
| 0.7
|-
| result_list_use_geturl
| Use the getURL() method to link to records in the list view rather than the default (which uses the -cursor parameter).
| 0
| 0.7
|-
| disable_ajax_record_details
| Whether to disable the ajax record details (the &apos;+&apos; sign beside each record in list view that expands to show the record details.
| 1
| 0.7
|-
| use_old_resultlist_controller
| As of Xataface 1.1, a new style result list controller is used that resembles facebook.  It is more slimmed down and is easier to manage.  If you prefer the old controller, set this preference to 1.
| 0
| 1.1
|}

===Inverse Preferences===

The following preferences perform the inverse of some of the options above. When these options are set to 1, their respective option is set to 0.

{| class=&quot;listing listing2&quot;
! Name
! Inverse
|-
| hide_nav_menu
| show_tables_menu
|-
| hide_view_tabs
| show_table_tabs
|-
| hide_result_controller
| show_result_controller
|-
| hide_table_result_stats
| show_result_stats
|-
| hide_search
| show_search
|}
</content>
	<keywords>preferences, prefs, getPreferences</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=105">
	<page_name>field__pushValue</page_name>
	<page_id>105</page_id>
	<page_title></page_title>
	<content>[[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 &apos;&apos;start_ip&apos;&apos; 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&apos;s delegate class.

&lt;code&gt;
class tables_ip_blocks {

	/**
	 * @param Dataface_Record $record The record we are pushing the value
	 *		into
	 * @param HTML_QuickForm_element $el The QuickForm widget that we are 
	 *      retrieving the value from.
	 */
	function start_ip__pushValue($record, $el){
		$val = ip2long($el-&gt;getValue());
		if ( $val !== false ){
			return sprintf(&apos;%u&apos;, $val );
		}
		return null;
	}
	
	function start_ip__pullValue($record, $el){
		$val = $record-&gt;val(&apos;start_ip&apos;);
		if ( $val )
			return long2ip($val);
		return $val;
	}
}
&lt;/code&gt;

==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.
</content>
	<keywords>pullValue, pushValue</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=104">
	<page_name>field__pullValue</page_name>
	<page_id>104</page_id>
	<page_title>field__pullValue delegate class method</page_title>
	<content>[[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 &apos;&apos;start_ip&apos;&apos; 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&apos;s delegate class.

&lt;code&gt;
class tables_ip_blocks {

	/**
	 * @param Dataface_Record $record The record we are pushing the value
	 *		into
	 * @param HTML_QuickForm_element $el The QuickForm widget that we are 
	 *      retrieving the value from.
	 */
	function start_ip__pushValue($record, $el){
		$val = ip2long($el-&gt;getValue());
		if ( $val !== false ){
			return sprintf(&apos;%u&apos;, $val );
		}
		return null;
	}
	
	function start_ip__pullValue($record, $el){
		$val = $record-&gt;val(&apos;start_ip&apos;);
		if ( $val )
			return long2ip($val);
		return $val;
	}
}
&lt;/code&gt;

==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.
</content>
	<keywords>pushValue, pullValue</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=115">
	<page_name>Using_RecordGrid</page_name>
	<page_id>115</page_id>
	<page_title>Using RecordGrid</page_title>
	<content>==Xataface RecordGrid Class and Template==

Also see [http://lamp.weblite.ca/dataface-0.6/docs/index.php?-table=Classes&amp;-action=browse&amp;ClassID=30| RecordGrid in the API Doc].


[[toc collapse=0]]

===Introduction===
As we learned in &apos;&apos;&apos;[http://xataface.com/documentation/tutorial/getting_started/dataface_actions Actions I: The Basics]&apos;&apos;&apos;, 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===
&lt;code&gt;
class actions_testTableAction {

	// Will be called from Xataface, if this action is called
	function handle(&amp;$params){
		$this-&gt;app =&amp; Dataface_Application::getInstance();  // reference to Dataface_Application object

		// Custom query
		$result = mysql_query(&quot;select * from testTable&quot;, $this-&gt;app-&gt;db());
		$body = &quot;&lt;br /&gt;&lt;br /&gt;&quot;;
		
		if(!$result)
		{
			// Error handling
			$body .= &quot;MySQL Error ...&quot;;
		}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-&gt;toHTML();	// Get the HTML of the RecordGrid
		}

		// Shows the content (RecordGrid or error message) in the Main Template
		df_display(array(&apos;body&apos; =&gt; $body), &apos;Dataface_Main_Template.html&apos;);
	}
}
&lt;/code&gt;

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=====
&lt;nowiki&gt;
&lt;img src=&quot;http://i89.photobucket.com/albums/k234/horchr/xataface/RecordGrid_blank.png?max_width=610&quot;/&gt;
&lt;/nowiki&gt;

=====Screenshot: ResultList=====

&lt;nowiki&gt;
&lt;img src=&quot;http://i89.photobucket.com/albums/k234/horchr/xataface/RecordList.png?max_width=713&quot;/&gt;
&lt;/nowiki&gt;


===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:

&lt;code&gt;
&lt;table id=&quot;{$id}&quot; class=&quot;listing {$class}&quot;&gt;
	&lt;thead&gt;
		&lt;tr&gt;
		{foreach from=$labels item=label}
		&lt;th&gt;{$label}&lt;/th&gt;
		{/foreach}
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		{section name=row loop=$data}
		&lt;tr class=&quot;listing {cycle values=&quot;odd,even&quot;}&quot;&gt;
			{foreach from=$columns item=col}
			&lt;td&gt;{$data[row][$col]}&lt;/td&gt;
			{/foreach}
		&lt;/tr&gt;
		{/section}
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/code&gt;

The magic happens in &lt;tr class=&quot;listing {cycle values=&quot;odd,even&quot;}&quot;&gt;
The {cycle values=&quot;odd,even&quot;} 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=====

&lt;nowiki&gt;
&lt;img src=&quot;http://i89.photobucket.com/albums/k234/horchr/xataface/RecordGrid_colored.png?max_width=610&quot;/&gt;
&lt;/nowiki&gt;


===Example completly imitating ResultList===

The Colored Example doesn&apos;t look like the ResulList? Its rows aren&apos;t as high as theres? That&apos;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
&lt;code&gt;
			while($row = mysql_fetch_assoc($result))	// Fetch all rows
			{
				// Maybe do something with the single rows
				$row[&apos;&lt;input type=&quot;checkbox&quot;&gt;&apos;] = &apos;&lt;input type=&quot;checkbox&quot;&gt;&apos;;
				$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(&apos;&lt;input type=&quot;checkbox&quot;&gt;&apos;, &apos;testID&apos;, &apos;name&apos;, &apos;description&apos;, &apos;number&apos;),	
				//Order and selection of the colums
				  null);	// No other labels defined -&gt; it uses keys of the associative array
			
			$body .= $grid-&gt;toHTML();	// Get the HTML of the RecordGrid
&lt;/code&gt;

Dataface_RecordGrid.html template
&lt;code&gt;
&lt;table id=&quot;{$id}&quot; class=&quot;listing {$class}&quot;&gt;
	&lt;thead&gt;
		&lt;tr&gt;
		{foreach from=$labels item=label}
		&lt;th&gt;&lt;a class=&quot;unmarked_link&quot;&gt;{$label}&lt;/a&gt;&lt;/th&gt;
		{/foreach}
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
		{section name=row loop=$data}
		&lt;tr class=&quot;listing {cycle values=&quot;odd,even&quot;}&quot;&gt;
			{foreach from=$columns item=col}
			&lt;td&gt;&lt;a class=&quot;unmarked_link&quot;&gt;{$data[row][$col]}&lt;/a&gt;&lt;/td&gt;
			{/foreach}
		&lt;/tr&gt;
		{/section}
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/code&gt;

=====Screenshot: RecordGrid completly imitating ResultList=====

&lt;nowiki&gt;
&lt;img src=&quot;http://i89.photobucket.com/albums/k234/horchr/xataface/RecordGrid_colored_checkboxes_links.png?max_width=610&quot;/&gt;
&lt;/nowiki&gt;

=====Screenshot: ResultList=====

&lt;nowiki&gt;
&lt;img src=&quot;http://i89.photobucket.com/albums/k234/horchr/xataface/RecordList.png?max_width=713&quot;/&gt;
&lt;/nowiki&gt;

===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.

&lt;code&gt;
class actions_testTableAction {

	// Will be called from Xataface, if this action is called
	function handle(&amp;$params){
		$this-&gt;app =&amp; Dataface_Application::getInstance();  // reference to Dataface_Application object

		$result_dummy = array(
			array(&apos;testID&apos; =&gt; &apos;1&apos;, &apos;name&apos; =&gt; &apos;testname&apos;, 
				&apos;description&apos; =&gt; &apos;a short description&apos;, &apos;number&apos; =&gt; &apos;258&apos;),
			array(&apos;testID&apos; =&gt; &apos;2&apos;, &apos;name&apos; =&gt; &apos;another name&apos;, 
				&apos;description&apos; =&gt; &apos;a bit longer description to this data set&apos;, &apos;number&apos; =&gt; &apos;946&apos;),
			array(&apos;testID&apos; =&gt; &apos;3&apos;, &apos;name&apos; =&gt; &apos;dummy name&apos;, 
				&apos;description&apos; =&gt; &apos;yea, a dummy data set!&apos;, &apos;number&apos; =&gt; &apos;1342&apos;),
			array(&apos;testID&apos; =&gt; &apos;4&apos;, &apos;name&apos; =&gt; &apos;not empty&apos;, 
				&apos;description&apos; =&gt; &apos;this data set isn\&apos;t empty ...&apos;, &apos;number&apos; =&gt; &apos;282&apos;),
			array(&apos;testID&apos; =&gt; &apos;5&apos;, &apos;name&apos; =&gt; &apos;your entry&apos;, 
				&apos;description&apos; =&gt; &apos;this entry is only for you&apos;, &apos;number&apos; =&gt; &apos;79&apos;),
			array(&apos;testID&apos; =&gt; &apos;6&apos;, &apos;name&apos; =&gt; &apos;no idea&apos;, 
				&apos;description&apos; =&gt; &apos;running out of ideas ...&apos;, &apos;number&apos; =&gt; &apos;203&apos;),
			array(&apos;testID&apos; =&gt; &apos;7&apos;, &apos;name&apos; =&gt; &apos;the last one&apos;, 
				&apos;description&apos; =&gt; &apos;the end&apos;, &apos;number&apos; =&gt; &apos;26841&apos;)
		);
		$body = &quot;&lt;br /&gt;&lt;br /&gt;&quot;;
		
		foreach($result_dummy as $row)	// Fetch all rows
		{
			// Maybe do something with the singe rows
			$row[&apos;&lt;input type=&quot;checkbox&quot;&gt;&apos;] = &apos;&lt;input type=&quot;checkbox&quot;&gt;&apos;;
			$data[] = $row;	// Add singe row to the data
		}

		$grid = new Dataface_RecordGrid($data,	// Create new RecordGrid with the data
			array(&apos;&lt;input type=&quot;checkbox&quot;&gt;&apos;, &apos;testID&apos;, &apos;name&apos;, &apos;description&apos;, &apos;number&apos;),	
			//Order and selection of the colums
			  null);	// No other labels defined -&gt; it uses keys of the associative array

		$body .= $grid-&gt;toHTML();	// Get the HTML of the RecordGrid

		// Shows the content (RecordGrid or error message) in the Main Template
		df_display(array(&apos;body&apos; =&gt; $body), &apos;Dataface_Main_Template.html&apos;);
	}
}
&lt;/code&gt;
</content>
	<keywords>RecordGrid, Dataface_RecordGrid, data in tabular form</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=98">
	<page_name>registration_form</page_name>
	<page_id>98</page_id>
	<page_title>Setting up User Registration</page_title>
	<content>[[toc]]

===Synopsis===

Xataface optionally enables you to allow users to register for an account in your application.  If your &apos;&apos;users&apos;&apos; 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&apos;s [[authentication]] and [http://xataface.com/documentation/tutorial/getting_started/permissions permissions] faculties.

===Enabling Registration===

To enable registration, simply add the following to the &apos;&apos;[[_auth]]&apos;&apos; section of the [[conf.ini file]]:

&lt;code&gt;
allow_register=1
&lt;/code&gt;

e.g. after adding this, your &apos;&apos;[[_auth]]&apos;&apos; section might look like:

&lt;code&gt;
[_auth]
     users_table=users
     username_column=username
     password_column=password
     allow_register=1
&lt;/code&gt;

After doing this, you&apos;ll notice a little &apos;&apos;Register&apos;&apos; 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 &quot;New Record&quot; form on your &apos;&apos;users&apos;&apos; 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 &apos;&apos;email&apos;&apos; field, it will use the user-entered address for email validation before activation is complete.

===Setting up Permissions to Support Registration===

&apos;&apos;&apos;Xataface &lt;= 1.2.4&apos;&apos;&apos;:   You must ensure that unlogged-in users have permission to add new records to the &apos;&apos;users&apos;&apos; table.  This means that your getPermissions() method on the users table should, at least, provide the &apos;&apos;new&apos;&apos; permission.  In addition these users must be granted the &apos;&apos;register&apos;&apos; permission in order to be able to register to begin with.

&apos;&apos;&apos;Xataface &gt;= 1.2.5&apos;&apos;&apos;:  You no longer need to provide the &apos;&apos;new&apos;&apos; permission to allow users to register.  You simply need to provide the &apos;&apos;register&apos;&apos; permission.

====Sample Permissions on Users Table====

In the tables/users/users.php file (assuming my &apos;&apos;users&apos;&apos; table is actually named &quot;users&quot;)

&lt;code&gt;
class tables_users {

    function getPermissions($record){
        if ( isAdmin() ) return null;
        $perms[&apos;register&apos;] = 1;
        return $perms;
     
    }
}
&lt;/code&gt;

&apos;&apos;&apos;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 &apos;&apos;new&apos;&apos; permission rather than the &apos;&apos;register&apos;&apos; permission, which opens up a small security hole since users could potentially just use the &quot;new&quot; action if they new the URL and by-pass the registration and activation email altogether&apos;&apos;&apos;.

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&apos;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&apos;t want users to be able to set their access level when the register for an account, and your &quot;users&quot; table will quite often contain some field like &quot;role&quot; which stores this information.  So the previous example is not quite realistic.  You will also need to restrict permissions on the &quot;role&quot; field (and any other fields that you want to prevent users from setting themselves.

&lt;code&gt;
function role__permissions(&amp;$record){
    if ( isAdmin() ) return null;
    return Dataface_PermissionsTool::NO_ACCESS();
}
&lt;/code&gt;

This will cut off the user&apos;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&apos;s registration.  This email contains a link back to the &apos;&apos;activate&apos;&apos; action of your Xataface application, which will create the user account and log the user in.  This implies that your &apos;&apos;users&apos;&apos; table must store an email address for your users.  If you add a field named &apos;&apos;email&apos;&apos; to the &apos;&apos;users&apos;&apos; table, Xataface will assume that you mean to use this field as the user&apos;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 &apos;&apos;email&apos;&apos; directive of the appropriate field in the [[fields.ini file]] for the &apos;&apos;users&apos;&apos; table.

&apos;&apos;&apos;Example: Assigning the my_addr field of the users table to be used for email validation&apos;&apos;&apos;:

In the tables/users/fields.ini file:
&lt;code&gt;
[my_addr]
    email=1
&lt;/code&gt;

====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 &apos;&apos;register&apos;&apos; action in the [[actions.ini file]] as follows:

In your application&apos;s [[actions.ini file]]:
&lt;code&gt;
[register &gt; register]
    email_validation=0
&lt;/code&gt;

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&apos;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]].
    </content>
	<keywords>registration form, _auth, authentication</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=181">
	<page_name>after_action_activate</page_name>
	<page_id>181</page_id>
	<page_title>after_action_activate Delegate Class Method</page_title>
	<content>Return to [[Application Delegate Class]]

[[toc]]


The &apos;&apos;&apos;after_action_activate&apos;&apos;&apos; hook is a method that can be defined in the [[Application Delegate Class]] which is called after an account has been activated via the registration process.  The full registration process goes as follows:

# User fills in registration form.
# An email is sent to the user with a link to activate their account.
# User clicks on activation link.
# User is taken back to the application and activation occurs, which consists of creating a new record in the &apos;&apos;&apos;users&apos;&apos;&apos; table.
# The &apos;&apos;after_action_activate&apos;&apos; trigger is called.

===Since===

This hook has been available since Xataface Version 1.2

===Example===

&lt;code&gt;
/**
 * A trigger to send the user a confirmation email after their account has been activated.
 * @params array $params Associative array of passed parameters.  Contains a single key &apos;record&apos;
 * with the Dataface_Record object of the users table with the user that was activated.
 */
function after_action_activate(array $params){
    $user = $params[&apos;record&apos;];
    
    mail($user-&gt;val(&apos;email&apos;), &apos;Your account is activated&apos;, &apos;Your account has been activated... etc..&apos;);
}
&lt;/code&gt;

===See Also===

* [[Application Delegate Class]]
* [[registration_form]] - More information user registration forms.
* [[beforeRegister]] - Trigger called before the user registration form is saved.
* [[afterRegister]] - Trigger called after registration form is saved.
* [[validateRegistrationForm]] - Validates the input into the registration form.
* [[sendRegistrationActivationEmail]] - Overrides the sending of the registration activation email.
* [[getRegistrationActivationEmailInfo]] - Overrides the activation email info.  Returns an associative array of the email details (e.g. subject, to, headers, etc...
* [[getRegistrationActivationEmailSubject]] - Returns the subject of the activation email.
* [[getRegistrationActivationEmailMessage]] - Returns the message body for the activation email.
* [[getRegistrationActivationEmailParameters]] - Returns the parameters for the actication email.
* [[getRegistrationActivationEmailHeaders]] - Returns the headers for the activation email.
</content>
	<keywords>Registration, activation, register, activate, users</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=78">
	<page_name>GettingStarted:relationships</page_name>
	<page_id>78</page_id>
	<page_title>Relationships</page_title>
	<content>==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 &apos;Course&apos; by adding a select list to the Course table form to select the Program that the Course belongs to.

From the &apos;Program&apos; side it is a little bit more complicated. There are no fields in the &apos;Program&apos; table that can be edited to add a &apos;Course&apos; to the list of courses in a &apos;Program&apos;, and it would be highly inconvenient to have to edit a &apos;Course&apos; record in order to add the course to a &apos;Program&apos;. What we want is a sort of &apos;Add Course&apos; button to add a course to a &apos;Program&apos;. 

===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 &apos;Program&apos; table to the &apos;Course&apos; table, the mirror (many-to-one) relationship from &apos;Course&apos; to &apos;Program&apos; is not automatically created. This method of defining relationships allows us to unambiguously refer to the source and destination tables of a relationship.

&apos;&apos;&apos;Definition 1:&apos;&apos;&apos; The &apos;&apos;source table&apos;&apos; of a relationship is the table on which a relationship is defined. For example if we define a relationship named &apos;Courses&apos; on the &apos;Program&apos; table to associate courses in a given program, then the &apos;Program&apos; table would be considered the source table of the relationship, and the &apos;Course&apos; table would be a destination table of the relationship.

&apos;&apos;&apos;Definition 2:&apos;&apos;&apos; The &apos;&apos;destination table&apos;&apos; 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. 

&apos;&apos;&apos;Definition 3:&apos;&apos;&apos; A &apos;&apos;domain table&apos;&apos; is a destination table which stores the object of the relationship. For example if we define a many-to-many relationship between the &apos;Program&apos; table and the &apos;Course&apos; 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 &apos;Course&apos; records to &apos;Program&apos; records. Let&apos;s call this table &apos;ProgramCourses&apos;. Each record of the &apos;ProgramCourses&apos; table would contain a 2 fields: a &apos;ProgramID&apos; field (to reference the program) and a &apos;CourseID&apos; field to reference the course. If we define the relationship from the point of view of a &apos;Program&apos; then the &apos;Program&apos; table would be the source table, the &apos;ProgramCourses&apos; table would be the join table, and the &apos;Course&apos; table would be the domain table.

Don&apos;t worry if these definitions and terms aren&apos;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 &apos;relationships.ini&apos; file inside the configuration folder for the table.

====Example 1: Adding a &apos;Courses&apos; relationship to the &apos;Program&apos; table====

We want to be able to associate multiple courses with each program. We do this by defining a relationship on the &apos;Program&apos; table as follows:

# Add a file named &apos;relationships.ini&apos; to the &apos;Program&apos; table&apos;s configuration folder (i.e., tables/Program/relationships.ini). Your application&apos;s directory structure should now look like:&lt;nowiki&gt;&lt;br/&gt;&lt;/nowiki&gt;[[Image:http://xataface.com/documentation/tutorial/getting_started/directory-structure-relationships.gif]]&lt;nowiki&gt;&lt;br/&gt;&lt;/nowiki&gt;Notice, in particular the addition of the &apos;relationships.ini&apos; file in the &apos;Program&apos; directory.
# Add the following to the &apos;relationships.ini&apos; file:&lt;code&gt;
[Courses]
	Course.ProgramID = &quot;$ProgramID&quot;
&lt;/code&gt;	

This little snippet defines a relationship named &apos;Courses&apos; on the &apos;Program&apos; table. &apos;Program&apos; is the source table. &apos;Course&apos; 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 &apos;ProgramID&apos; field in the source record. This relationship specifies that courses whose &apos;ProgramID&apos; field matches the value of the &apos;ProgramID&apos; 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&apos;s check out our changes. Since we have defined the relationship on the &apos;Program&apos; table, we will click on the &apos;Program&apos; link in the navigation menu:
[[Image:http://xataface.com/documentation/tutorial/getting_started/course-relationship-defined-1.gif]]

Notice that there is now a &apos;course&apos; 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 &apos;Courses&apos; relationship). If it says that &quot;No records matched the request&quot; or something to that effect, then you don&apos;t have any Course records in the relationship yet. Just click the &quot;Add New Courses Record&quot; 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 &quot;Add New Courses&quot; 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 &apos;Courses&apos; 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 &apos;ProgramCourses&apos; to the database. The SQL table definition for this table should be something like:&lt;code&gt;
CREATE  TABLE  `ProgramCourses` (
	`ProgramID` INT( 11  )  NOT  NULL ,
	`CourseID` INT( 11  )  NOT  NULL ,
	PRIMARY  KEY (  `ProgramID` ,  `CourseID`  ) 
	) 
&lt;/code&gt;&lt;nowiki&gt;&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;
The above defined table will serve as a join table between &apos;Program&apos; and &apos;Course&apos;
&lt;/p&gt;&lt;/nowiki&gt;
# Since this is now going to be a many-to-many relationship, we no longer need the &apos;ProgramID&apos; field in the &apos;Course&apos; table. (Do not confuse this with the ProgramID field in the &apos;Program&apos; 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:&lt;code&gt;
INSERT  INTO ProgramCourses( ProgramID, CourseID ) 
	SELECT ProgramID, CourseID
	FROM Course
&lt;/code&gt;&lt;nowiki&gt;&lt;p&gt;	
And now we can remove the &apos;ProgramID&apos; field from the &apos;Course&apos; table.
ALTER  TABLE  Course  DROP  ProgramID&lt;/p&gt;&lt;/nowiki&gt;
# Finally, we will need to modify the relationship definition in the relationships.ini file of the &apos;Program&apos; table:&lt;code&gt;
[Courses]
	Course.CourseID = ProgramCourses.CourseID
	ProgramCourses.ProgramID = &quot;$ProgramID&quot; 
&lt;/code&gt;&lt;nowiki&gt;&lt;p&gt;
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.&lt;/p&gt;&lt;/nowiki&gt;
# Now we can check our application for changes. Go to the &apos;Program&apos; table in your application (using your web browser) and click on the &apos;courses&apos; tab once again:&lt;nowiki&gt;&lt;br/&gt;&lt;/nowiki&gt;[[Image:http://xataface.com/documentation/tutorial/getting_started/multi-relationship.gif]]&lt;nowiki&gt;
&lt;p&gt;
This looks almost the same as before. Notice, however that now there is an &quot;Add Existing Courses Record&quot; button at the top. This is because with a many-to-many relationship, you are able to add related records in 2 ways:&lt;/p&gt;&lt;/nowiki&gt;
## 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&apos;s look at the relationships.ini file from example 1:&lt;code&gt;
[Courses]
	Course.ProgramID = &quot;$ProgramID&quot;
&lt;/code&gt;

This also could have been defined as follows:&lt;code&gt;
[Courses]
	__sql__ = &quot;SELECT * FROM Course WHERE ProgramID=&apos;$ProgramID&apos;&quot;
&lt;/code&gt;

&apos;&apos;&apos;Note: Make sure you use two underscores on either side of &apos;sql&apos; in the above example. It should be &apos;__sql__&apos; not &apos;_sql_&apos;.&apos;&apos;&apos;

The two syntaxes are equivalent. In fact, the former will be converted into the later by Xataface behind the scenes.

Now let&apos;s look at example 2&apos;s relationships.ini file:&lt;code&gt;
[Courses]
	Course.CourseID = ProgramCourses.CourseID
	ProgramCourses.ProgramID = &quot;$ProgramID&quot; 
&lt;/code&gt;

This could have been written as:&lt;code&gt;
[Courses]
	__sql__ = &quot;SELECT * 
		FROM ProgramCourses, Course 
		WHERE Course.CourseID = ProgramCourses.CourseID 
		AND ProgramCourses.ProgramID = &apos;$ProgramID&apos;&quot;
&lt;/code&gt;

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:&lt;code&gt;
[Courses]
	__sql__ = &quot;SELECT * 
		FROM ProgramCourses pc 
		INNER JOIN Course c ON pc.CourseID = c.CourseID 
		WHERE pc.ProgramID = &apos;$ProgramID&apos;&quot;
&lt;/code&gt;

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 &apos;=&apos; comparisons, and &apos;AND&apos; conjunctions. i.e., it cannot receive an &apos;OR&apos; conjunction, nor can comparisons be done using &apos;&gt;&apos;, or &apos;&lt;&apos;. This is because given &apos;AND&apos; and &apos;=&apos; conjunctions it is easy for Xataface to be able to add records that will satisfy the relationship. If an &apos;OR&apos; 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]</content>
	<keywords>relationships</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=111">
	<page_name>Relationship_Permissions</page_name>
	<page_id>111</page_id>
	<page_title>Relationship Permissions</page_title>
	<content>[[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: &apos;&apos;people&apos;&apos; and &apos;&apos;publications&apos;&apos;, and we have a relationship from &apos;&apos;publications&apos;&apos; table to the &apos;&apos;people&apos;&apos; table called &apos;&apos;publication_authors&apos;&apos;.

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 &apos;&apos;add new related record&apos;&apos; permission on the &apos;&apos;publications&apos;&apos; table record, then the user will still be able to add new people, via the &quot;Add related people record&quot; 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=&quot;listing listing2&quot;
|-
! 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&apos;s delegate class, where &apos;&apos;relationshipname&apos;&apos; is the name of the relationship.

e.g.  Consider the relationship &apos;&apos;manufacturers&apos;&apos;:
&lt;code&gt;
function rel_manufacturers__permissions($record){
	// $record is a Dataface_Record object
	return array(
		&apos;view related records&apos; =&gt; 0
	);
}
&lt;/code&gt;
This will tell xataface that users should not be able to view related records on the &apos;&apos;manufacturers&apos;&apos; 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&apos;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 &apos;&apos;products&apos;&apos; table:

&lt;code&gt;
[parts]
    parts.part_id=product_parts.part_id
    product_parts.product_id=&quot;$product_id&quot;

[editors]
    product_editors.product_id=&quot;$product_id&quot;
&lt;/code&gt;


===Application Permissions : Very Restrictive===

Like a good boyscout, we define our default permissions in the [[Application Delegate Class]] to be very restrictive: Don&apos;t let anyone do anything.

&lt;code&gt;
class conf_ApplicationDelegate {
    function getPermissions($record){
        return Dataface_PermissionsTool::NO_ACCESS();
    }
}
&lt;/code&gt;


===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:
&lt;code&gt;
class tables_products {
    function getPermissions($record){
        $user = Dataface_AuthenticationTool::getInstance()-&gt;getLoggedInUser();
        if ( $user and $record and $record-&gt;val(&apos;owner_username&apos;) == $user-&gt;val(&apos;username&apos;)){
        	// Give the record owner Edit permissions on the product
        	return Dataface_PermissionsTool::getRolePermissions(&apos;EDIT&apos;);
        }
        
        // Everybody else gets read only access to the products table.
        return Dataface_PermissionsTool::READ_ONLY();
    }
}

&lt;/code&gt;

===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.  &apos;&apos;&apos;THIS IS VERY BAD!!!&apos;&apos;&apos; 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&apos;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 &apos;&apos;products&apos;&apos; 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):&lt;code&gt;
function __sql__(){
    return sprintf(&quot;select p.*, pe.editor_username from products p
                left join product_editors pe on p.product_id=pe.product_id
                where pe.editor_username=&apos;%s&apos;&quot;,
                addslashes(
                   Dataface_AuthenticationTool::getInstance()-&gt;getLoggedInUsername()
                )
            );
                
}&lt;/code&gt;

This will result in a situation where product records will have an additional field &apos;&apos;editor_username&apos;&apos; which will either be blank if the current user is not an editor for the product; or will contain the current user&apos;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.

&lt;code&gt;
class tables_products {
    function getPermissions($record){
        $user = Dataface_AuthenticationTool::getInstance()-&gt;getLoggedInUser();
        if ( $user and $record and $record-&gt;val(&apos;owner_username&apos;) == $user-&gt;val(&apos;username&apos;)){
        	// Give the record owner Edit permissions on the product
        	return Dataface_PermissionsTool::getRolePermissions(&apos;EDIT&apos;);
        }
        
        if ( $user and $record and $record-&gt;val(&apos;editor_username&apos;) == $user-&gt;val(&apos;username&apos;) ){
            // If the user is an editor, we give them edit permissions
            // also
            return Dataface_PermissionsTool::getRolePermissions(&apos;EDIT&apos;);
        }
        
        
        if ( $user ){
        // Other logged in users have read only access
            $perms = Dataface_PermissionsTool::READ_ONLY();
            $perms[&apos;new&apos;] = 1; // We&apos;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;
    }
}

&lt;/code&gt;

===Removing Editor Access to the Editor Relationship===

You&apos;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&apos;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 &apos;&apos;editors&apos;&apos; relationship.

In the tables/products/products.php delegate class:

&lt;code&gt;

function rel_editors__permissions($record){
    $user = Dataface_AuthenticationTool::getInstance()-&gt;getLoggedInUser();
	if ( $user and $record and $record-&gt;val(&apos;owner_username&apos;) == $user-&gt;val(&apos;username&apos;)){
		// Owners should just get their normal permissions
		return null;
	}
	
	if ( $user and $record and $record-&gt;val(&apos;editor_username&apos;) == $user-&gt;val(&apos;username&apos;) ){
		// If the user is an editor, we give them edit permissions
		// also
		return array(
		    &apos;view related records&apos; =&gt; 0,
		    &apos;add new related record&apos; =&gt; 0,
		    &apos;add existing related record&apos; =&gt; 0,
		    &apos;remove related record&apos; =&gt; 0,
		    &apos;delete related record&apos; =&gt; 0
		    );
	}
	
	// Other users just get their normal permissions
	return null;

}

&lt;/code&gt;


===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&apos;t be able to edit it because they are neither an editor nor the owner of the product.  We&apos;ll fix this by assigning the current user as the product&apos;s owner using the [[beforeSave]] trigger in the products delegate class:

&lt;code&gt;
function beforeSave($record){
	$user = Dataface_AuthenticationTool::getInstance()-&gt;getLoggedInUser();
	if ( $user ){
    	$record-&gt;setValue(&apos;owner_username&apos;, $user-&gt;val(&apos;username&apos;));
    }
}
&lt;/code&gt;

===Testing Out Our Solution===

In your testing of the solution, you should find the following:

# Trying to access any table other than the &apos;&apos;products&apos;&apos; table should result in a &apos;&apos;permission denied&apos;&apos; error.
# If you access the &apos;&apos;products&apos;&apos; table, you should be able to see a list of existing products, and the &quot;Add New Record&quot; 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 &apos;&apos;parts&apos;&apos; and &apos;&apos;editors&apos;&apos; 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&apos;t be able to see the &apos;&apos;editors&apos;&apos; 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.
</content>
	<keywords>relationships, permissions, rel_relationshipname__permissions, getPermissions, permissions.ini</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=20">
	<page_name>relationships.ini_file</page_name>
	<page_id>20</page_id>
	<page_title>relationships.ini_file</page_title>
	<content>==relationships.ini File Reference==

[[toc]]

===Overview===

The relationship.ini file is a configuration file which is associated with a single table of a database application.  It provides metadata about the table&apos;s relationships to other tables to help Xataface dictate how they should be included in the application.  

===Field Directives===

The following directives may be added to a field&apos;s section of the relationship.ini file to customize the field&apos;s behavior.  Some directives are not applicable to all fields.

{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Version
|-
| __sql__
| The SQL query that defines this relationship. 
| all
|-
| [[action:visible]]
| A boolean value (0 or 1) that indicates whether this relationship should be visible in the record tabs.
| all
|-
| [[action:condition]]
| An expression that evaluates to a boolean that determines at runtime whether the relationship&apos;s tab should appear in the record tabs.
| all
|-
| [[action:delegate]]
| The name of an alternative action that can be used instead of the standard related records list.  One possible value for this would be &quot;related_records_checkboxes&quot; which would provide the user with a checkbox group to select the records that should be part of the relationship rather than the usual related record list.
| 1.0
|-
| [[section:limit]]
| Integer.  The number of records to show in the related record sections (in the view tab).  Default is 5.
| 1.0
|-
| [[section:visible]]
| Boolean value (0 or 1) indicating whether the relationship information should appear as a section on the left side of the table.
| all
|-
| [[actions:addexisting]]
| Boolean value (0 or 1) indicating whether the action to add existing records should exist in this relationship.
| all
|-
| [[actions:addnew]]
| Boolean value (0 or 1) indicating whether the action to add news records should exist in this relationship.
| all
|-
| [[action:label]]
| The label that appears in the relationship tab for this relationship. 
| all
|-
| [[list:type]]
| Optional type of list to use for the related record list.  Possible value: &quot;treetable&quot;
| 0.8
|-
| [[meta:class]]
| An optional special class to assign to the relationship.  E.g. &quot;parent&quot; or &quot;children&quot;.
| 0.8
|-
| [[metafields:order]]
| If the relationship should have a default order this specifies the field that should be used for this sort. 
| all
|-
| [[visibility:fieldName]]
| If given the value hidden will make that particular fieldName disappear in the relationship.  This will only be applied for that particular relationship.  
| all
|-
| [[visibility:find]]
| If given the value hidden this will cause the related fields to not appear on the find form.  Normally each relationship is provided a section of the find form to enable users to find records that contain at least one match in the related records.  
| 1.3rc4
|-
| [[vocabulary:existing]]
| Specifies a valuelist that can be used to provide the set of records that can be added to this relationship.  If target table has a single column primary key then the valuelist should use the primary key for the value.  If it has a multi-column primary key, then the value should be in the form key1=value1&amp;key2=value2 etc...  See also [[relationshipname__getAddableValues]] delegate class method for a programatic solution.
| 1.0
|}

==Relationship Permissions==

See [[Relationship Permissions]]

==See Also==

* [http://xataface.com/documentation/tutorial/getting_started/relationships Getting started with relationships]</content>
	<keywords>relationships.ini file, relationships</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=40">
	<page_name>Introduction_to_RSS_Feeds_in_Xataface</page_name>
	<page_id>40</page_id>
	<page_title>Introduction_to_RSS_Feeds_in_Xataface</page_title>
	<content>==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&apos;s RSS article]:

&quot;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 &quot;feed&quot;, &quot;web feed&quot;,[3] or &quot;channel&quot;) 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 &quot;RSS reader&quot;, &quot;feed reader&quot;, or &quot;aggregator&quot;, 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&apos;s URI (often referred to informally as a &quot;URL&quot;, 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&apos;s subscribed feeds regularly for new work, downloads any updates that it finds, and provides a user interface to monitor and read the feeds.&quot;

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&apos;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 &apos;&apos;news&apos;&apos; table, so he navigates to the &apos;&apos;list&apos;&apos; tab of the &apos;&apos;news&apos;&apos; 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 &apos;&apos;news&apos;&apos; table.  When new records are inserted, he&apos;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 &apos;&apos;news&apos;&apos; table that contains the phrase &quot;Buffalo Bills&quot;, because he is a Buffalo Bills fan.  So he navigates to the &apos;&apos;news&apos;&apos; table, and does a search for the phrase &quot;Buffalo Bills&quot;.  Then he clicks on the &quot;RSS Feed&quot; 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 &apos;&apos;news&apos;&apos; items containing the phrase &quot;Buffalo Bills&quot;.  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 &apos;&apos;authors&apos;&apos; table and the &apos;&apos;books&apos;&apos; table named &apos;&apos;publications&apos;&apos;.  You can subscribe to the RSS feed for his publications by navigating to the &apos;&apos;publications&apos;&apos; tab for that author, then clicking on the &quot;RSS Feed&quot; icon in the upper right.  Now whenever this author adds a new book to his publications list, you&apos;ll be notified via RSS.



===Example usage in Xataface===

# A user wants to be alerted whenever a new item is inserted into the &apos;&apos;news&apos;&apos; table, so he navigates to the &apos;&apos;list&apos;&apos; tab of the &apos;&apos;news&apos;&apos; 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 &apos;&apos;news&apos;&apos; table.  When new records are inserted, he&apos;ll receive alerts in his RSS reader.
# A user wants to be alerted whenever a new record about &quot;Wayne Gretzky&quot; is inserted in to the &apos;&apos;news&apos;&apos; table.  He navigates to the &apos;&apos;news&apos;&apos; table, then performs a search for &quot;Wayne Gretzky&quot; using the top right search box.  Then, he clicks on the &quot;RSS Feed&quot; icon in the upper right of the result list.  Now, whenever a new item is inserted with the phrase &quot;Wayne Gretzky&quot;, 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=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[getFeedItem]]
| For RSS Feeds, overrides the defaults and returns an associative array with feed elements for a particular record
| 1.0
|-
| [[getFeed]]
| For RSS feeds, overrides the default feed for a query, returning an array of feed items.
| 1.0
|-
| getFeedSource
| Overrides the default feed source parameter for an RSS feed.
| 1.0
|-
| 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 &apos;&apos;[_feed]&apos;&apos; section of your [[conf.ini file]].  This is sort of a &quot;one size fits all&quot; approach where all feeds generated from your application will share the same title.

E.g.

&lt;code&gt;
[_feed]
    title=&quot;My Site News&quot;
    description=&quot;News updates from my site&quot;
    link=&quot;http://www.example.com&quot;
&lt;/code&gt;

However, if we want our feed&apos;s information to depend on the user&apos;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.

&lt;code&gt;
function getFeed($query=array()){
    $params = array();
    if ( @$query[&apos;-search&apos;] ) $params[&apos;title&apos;] = &apos;&quot;&apos;.$query[&apos;-search&apos;].&apos;&quot; results&apos;;
    else $params[&apos;title&apos;] = &apos;All records from my table&apos;;
    return $params;
}
&lt;/code&gt;

Notice that I don&apos;t need to define all possible parameters.  Any parameters that I don&apos;t define will be provided automatically by Xataface, or it will simply use the values specified in your &apos;&apos;[_feed]&apos;&apos; 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&apos;t specify it explicitly, but you&apos;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.

&lt;code&gt;
function getFeedItem(&amp;$record)){
    return array(
        &apos;description&apos; =&gt; $record-&gt;val(&apos;body&apos;)
    );
}
&lt;/code&gt;

Once again, notice that we don&apos;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.


</content>
	<keywords>RSS Feeds</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=7">
	<page_name>Delegate_class_methods</page_name>
	<page_id>7</page_id>
	<page_title>Delegate_class_methods</page_title>
	<content>==Delegate Class Reference==

[[toc]]

A delegate class is a PHP class that complements a particular table with custom bahaviors.  Basic table metadata can be supplied using the [[fields.ini file]], however some things are better customized using PHP.

===Delegate Class Location===

The delegate class should be located in a file named TABLENAME.php (where TABLENAME is the name of the table with which the delegate class is associated) inside the table&apos;s [[table configuration directory|configuration directory]].  E.g. given a table named &quot;people&quot;, you would place the delegate class in the file &quot;tables/people/people.php&quot;

===Basic Delegate Class===

&lt;code&gt;
&lt;?php
class tables_people {}
?&gt;
&lt;/code&gt;

===Available Methods===

====Table Settings====

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[sql delegate method|__sql__]]
| Defines the SQL query that can be used to fetch records of this table.  This is identical to the [[fields.ini file]] [[__sql__]] directive, except that by defining it in the delegate class you have more flexibility.
| 1.0
|}

====Permissions====

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[getPermissions]]
| Returns the permissions available for a given record.
| 0.6
|-
| getRoles
| Returns the roles allowed for a given record.
| 1.0
|-
| [[__field__permissions]]
| Returns the default permissions for a field of a given record.
| 1.0
|-
| __field__roles
| Returns the default roles for a field of a given record.
| 1.0
|-
| [[fieldname__permissions]]
| Returns the permissions that are allowed for the field &quot;fieldname&quot; on a given record.
| 0.7
|-
| fieldname__roles
| Returns the roles that are allowed for the field &quot;fieldname&quot; on a given record.
| 1.0
|-
| rel_relationshipname__permissions
| Returns the permissions pertaining to the relationship &apos;&apos;relationshipname&apos;&apos; on a given record.
| 1.0
|-
| rel_relationshipname__roles
| Returns the role or roles pertaining to the relationship &apos;&apos;relationshipname&apos;&apos; on a given record.
| 1.0
|}

====Triggers====

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[after_action_edit]]
| Trigger called after the edit action is succesfully completed.
| 0.7
|-
| [[after_action_new]]
| Trigger called after the new action is successfully completed.
| 0.7
|-
| [[after_action_delete]]
| Trigger called after the delete action is successfully completed.
| 0.7
|-
| [[afterAddExistingRelatedRecord]]
| Trigger called after an existing related record is added.
| 0.5
|-
| [[aftereAddNewRelatedRecord]]
| Trigger called after a new related record is added.
| 0.5
|-
| [[afterCopy]]
| Trigger called after a record is copied.
| 1.3
|-
| [[afterDelete]]
| Trigger called after a record is deleted.
|0.5
|-
| [[afterAddRelatedRecord]]
| Trigger called after a related record of this table is added (either an existing record or a new record).
| 0.5
|-
| [[afterRemoveRelatedRecord]]
| Trigger called after a related record is removed from a relationship.
| 1.1.6
|-
| [[afterInsert]]
| Trigger called after a given record is inserted.
| 0.5
|-
| [[afterSave]]
| Trigger called after a given record is saved (insert or update).
| 0.5
|-
| [[afterUpdate]]
| Trigger called after a given record is updated.
| 0.5
|-
| [[beforeAddExistingRelatedRecord]]
| Trigger called before an existing related record is added.
| 0.5
|-
| [[beforeAddNewRelatedRecord]]
| Trigger called before a new related record is added.
| 0.5
|-
| [[beforeAddRelatedRecord]]
| Trigger called before a related record of this table is added (either an existing record or a new record).
| 0.5
|-
| [[beforeCopy]]
| Trigger called before a record is copied.
| 1.3
|-
| [[beforeDelete]]
| Trigger called before a record is deleted.
| 0.5
|-
| [[beforeRemoveRelatedRecord]]
| Trigger called before a related record is removed.
| 1.1.6
|-
| [[beforeSave]]
| Trigger called before a given record is saved (insert or update).
| 0.5
|-
| [[beforeInsert]]
| Trigger called before a given record is inserted.
| 0.5
|-
| [[beforeUpdate]]
| Trigger called before a given record is updated.
| 0.5
|-
| [[init]]
| This method is called the first time the table is loaded.  It allows you to specify initialization details.
| 0.8
|}


====Field Filters====

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| fieldname__htmlValue
| Returns the value of the field &quot;fieldname&quot; for a given record as HTML.
| 0.5
|-
| fieldname__display
| Returns the value of the field &quot;fieldname&quot; appropriate for displaying.
| 0.5
|-
| [[fieldname__default]]
| Returns the default value for the field &apos;&apos;fieldname&apos;&apos;.  New record forms will be prepopulated with this value.
| 0.7
|-
| [[fieldname__validate]]
| Validates the input for the field &apos;&apos;fieldname&apos;&apos;.
| 0.6
|-
| fieldname__parse
| Parses the input value for the field &apos;&apos;fieldname&apos;&apos;.  This is called by Xataface inside the setValue() method or each record to normalize input values before they are stored in the object (not the database).
| 0.5
|-
| fieldname__toString
| Converts the value of the field &apos;&apos;fieldname&apos;&apos; to a string.  This string representation is used as the basis for most higher level data retrieval methods (such as serialize and display).  This could be treated as an inverse to the [[fieldname__parse]] method.
| 0.5
|-
| fieldname__serialize
| Converts a value of the field &apos;&apos;fieldname&apos;&apos; to be saved in the database.  This should return a string representation of the value that is suitable for database storage.
| 0.5
|-
| fieldname__link
| A link that appears beside the field &apos;&apos;fieldname&apos;&apos; on the edit form.
| 0.6
|-
| [[field__pushValue]]
| Converts form input for field &apos;&apos;fieldname&apos;&apos; to be ready to store in a Dataface_Record.
| 0.6
|-
| [[field__pullValue]]
| Converts a value for field &apos;&apos;fieldname&apos;&apos; in a Dataface_Record object to be ready to be inserted as a value on an HTML form.
| 0.6
|-
| [[field__fieldname]]
| Effectively creates a calculated field named &quot;fieldname&quot; available on the given record.
| 0.6
|-
| [[no_access_text]]
| Replace the default NO ACCESS permission text with another text.
| 1.1.6
|-
| [[no_access_link]]
| Replace the default link of the NO ACCESS permission link with another link.
| 1.1.6
|}

====Template Customization====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[block__blockname]]
| Outputs content that is meant to override a slot or a block named &quot;blockname&quot;.
| 0.6
|}

====List Tab Customization====

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| css__tableHeaderCellClass
| Returns a custom CSS class for a table header cell (th tag) in the list view.  Takes the name of a table column as a parameter.
| 2.0alpha2
|-
| css__tableRowClass
| Returns a custom CSS class for a table row (tr tag) in list view.  Takes a Dataface record as a parameter.
| 1.2
|-
| fieldname__renderCell
| Overrides the table cell content for the &quot;fieldname&quot; field in list view with custom HTML.
| 1.0
|-
| renderRow
| Overrides the the html used for a row in list view for the given record.
| 0.7
|-
| renderRowHeader
| Overrides the header for the table in list view.
| 0.7
|-
| renderRelatedRow
| Overrides the html used for a row in a related record list for a given related record.
| 1.0 beta 4
|-
| renderRelatedRowHeader
| Overrides the html used for the header in a related list.
| 1.0 beta 4
|}

====Record Metadata====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[getBreadCrumbs]]
| Returns the bread crumbs (i.e. you are here) for a given record as an associative array of path parts.
| 0.6
|-
| [[getChildren]]
| Returns a list of Dataface_Record objects that are to be considered children of the given record.
| 0.8
|-
| [[getCreated]]
| Returns a unix timestamp marking the date that a record was created. 
| 0.9
|-
| getDescription
| Returns a string description summary of this record.  This is used for indexing, RSS feeds, and anywhere that a brief summary of a record is appropriate.
| 0.7
|-
| getPublicLink
| Returns the public URL of this record (in case it is different than the standard URL).
| 0.8
|-
| getTitle
| Returns the title for a given record.  The title is used in various parts of the application to represent the record.
| 0.5
|-
| [[getURL]]
| Overrides the getURL() method for a record.  Returns the URL that should be used to display the given record.
| 0.6
|-
| titleColumn
| Returns a string SQL select expression that is used to describe the title of records.
| 0.5
|}

====View Tab Customization====

{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[How_to_Add_Custom_Sections_to_View_Tab|section__sectionname]]
| Defines a section to be displayed in the view tab for the given record.
| 0.7
|}


====Search Setup====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| getSearchableText
| If [[_index|Indexing]] is turned on, then this returns the text that should be stored in the index for this record for searchability.
| 1.0
|}

====RSS Feed Customization====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[getFeedItem]]
| For RSS Feeds, overrides the defaults and returns an associative array with feed elements for a particular record
| 1.0
|-
| [[getFeed]]
| For RSS feeds, overrides the default feed for a query, returning an array of feed items.
| 1.0
|-
| getFeedSource
| Overrides the default feed source parameter for an RSS feed.
| 1.0
|-
| [[getRelatedFeed]]
| For RSS feeds, overrides the default feed for a related feed.
| 1.0
|-
| getRSSDescription
| Overrides the default generated RSS description for a record.
| 1.0
|}

===XML Output Customization===
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[toXML]]
| Overrides the default XML produced for a record in the [[export xml]] action.  Returns an XML string.
| 1.2.7
|-
| [[getXMLHead]]
| Returns a string to be included at the beginning of XML output for a particular record. (just inside the opening tag).
| 1.2.7
|-
| [[xmlTail]]
| Returns a string to be included at the end of XML output for a particular record. (just inside the closing tag).
| 1.2.7
|}

====Valuelist Customization====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[valuelist__valuelistname]]
| Defines a valuelist named &apos;&apos;valuelistname&apos;&apos;.
| 0.7
|}


====Importing Records====
{| class=&quot;listing listing2&quot;
! Name
! Description
! Version
|-
| [[__import__filtername]]
| Defines an import filter to named &apos;&apos;filtername&apos;&apos; which is used to import records into the table.
| 0.7
|}
</content>
	<keywords>RSS,Feeds,delegate classes, triggers</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=88">
	<page_name>secure</page_name>
	<page_id>88</page_id>
	<page_title>secure fields.ini directive</page_title>
	<content>[[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:

&lt;code&gt;
[pdf_report]
    Type=container
    allowed_extensions=&quot;pdf&quot;
    savepath=&quot;uploads&quot;
    url=&quot;uploads&quot;
&lt;/code&gt;


Now if we upload a file named &quot;foo.pdf&quot; 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:

&lt;code&gt;
[pdf_report]
    Type=container
    allowed_extensions=&quot;pdf&quot;
    savepath=&quot;uploads&quot;
    url=&quot;uploads&quot;
    secure=1
&lt;/code&gt;

In this case it will still upload files to the &apos;&apos;uploads&apos;&apos; directory, but all of the links generated in the Xataface interface (and via the &apos;&apos;display()&apos;&apos; and &apos;&apos;htmlValue()&apos;&apos; methods) will be for a URL like:
  http://www.example.com/path/to/myapp/index.php?-action=getBlob&amp;-table=mytable&amp;-field=pdf_report&amp;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:
&lt;code&gt;
deny from all
&lt;/code&gt;

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:

* &apos;&apos;&apos;404&apos;&apos;&apos; - If either the record does not exist, or the record&apos;s specified container field is empty.
* &apos;&apos;&apos;403&apos;&apos;&apos; - If the current user doesn&apos;t have permission to access this record.
* &apos;&apos;&apos;500&apos;&apos;&apos; - If there is another error.  The actual error will be written to the error log.</content>
	<keywords>secure,fields.ini file</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=23">
	<page_name>xataface_templates</page_name>
	<page_id>23</page_id>
	<page_title>xataface_templates</page_title>
	<content>==Xataface Templates==

[[toc]]

Xataface uses the [http://smarty.php.net Smarty Template Engine] to power all of its templates.  Templates are stored in the one of the following locations:

* %XATAFACE_ROOT%/Dataface/templates
* %SITE_ROOT%/templates

Where %XATAFACE_ROOT% is the Xataface directory (includes files such as dataface-public-api.php), and %SITE_ROOT% is the path to your application.

You may also have subdirectories within these templates directories.

===Cascading Templates===

Xataface uses a simple cascading technique for deciding which template to use.  If there are templates in the %SITE_ROOT%/templates and %XATAFACE_ROOT%/Dataface/templates directories with the same name, then Xataface will use the one in the %SITE_ROOT%/templates directory.  In this way, you are able to override any of Xataface&apos;s core templates by adding one of the same name to your %SITE_ROOT%/templates directory.

The most common template to override is the Dataface_Main_Template.html template which defines the look and feel for the entire application (e.g. header, footer, etc...).  Hence, if you wanted to customize the look &amp; feel of your application, you would likely start by copying %XATAFACE_ROOT%/Dataface/templates/Dataface_Main_Template.html into the %SITE_ROOT%/templates directory and make modifications to it as desired.

===Useful Smarty Tags introduced by Xataface===

In addition to the standard set of Smarty tags, Xataface templates provide some of its own.

==Xataface Templates==

Xataface uses the [http://smarty.php.net Smarty Template Engine] to power all of its templates.  Templates are stored in the one of the following locations:

* %XATAFACE_ROOT%/Dataface/templates
* %SITE_ROOT%/templates

Where %XATAFACE_ROOT% is the Xataface directory (includes files such as dataface-public-api.php), and %SITE_ROOT% is the path to your application.

You may also have subdirectories within these templates directories.

===Cascading Templates===

Xataface uses a simple cascading technique for deciding which template to use.  If there are templates in the %SITE_ROOT%/templates and %XATAFACE_ROOT%/Dataface/templates directories with the same name, then Xataface will use the one in the %SITE_ROOT%/templates directory.  In this way, you are able to override any of Xataface&apos;s core templates by adding one of the same name to your %SITE_ROOT%/templates directory.

The most common template to override is the Dataface_Main_Template.html template which defines the look and feel for the entire application (e.g. header, footer, etc...).  Hence, if you wanted to customize the look &amp; feel of your application, you would likely start by copying %XATAFACE_ROOT%/Dataface/templates/Dataface_Main_Template.html into the %SITE_ROOT%/templates directory and make modifications to it as desired.

===Useful Smarty Tags introduced by Xataface===

In addition to the standard set of Smarty tags, Xataface templates provide some of its own.

{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Version
|-
| [[templates:tags:use_macro|use_macro]]
| Include another template with the option to override certain sections.
| 0.6
|-
| define_slot
| Marks a section that can be overridden by other templates that include this one via the use_macro tag.
| 0.6
|-
| fill_slot
| Overrides content in a template that has been included via the use_macro tag.
| 0.6
|-
| block
| Marks an insertion point where content can be inserted by delegate classes and modules.
| 0.6
|-
| load_record
| Loads a [http://dataface.weblite.ca Dataface_Record] object from the database to be used in the template.
| 0.6
|-
| group
| Groups an array of records together based on a field value.
| 0.6
|-
| img
| Displays a thumbnail of an image.
| 0.6
|-
| actions
| Loads an associative array of actions defined in the actions.ini file, based on certain criteria.
| 0.6
|-
| actions_menu
| Displays a menu of actions based on certain criteria.
| 0.6
|-
| record_actions
| A specialization of the actions_menu tag.  This displays a menu of actions only in the record_actions category.
| 0.6
|-
| record_tabs
| A specialization of the actions_menu tag.  This displays a menu of actions only in the record_tabs category.
| 0.6
|-
| result_controller
| Displays the paging controls for the current table&apos;s records.   Use this for any listing of records.
| 0.6
|-
| result_list
| Displays the result list (from the list tab) for the current request.
| 0.6
|-
| related_list
| Displays the related records list for the current request.
| 0.6
|-
| bread_crumbs
| Displays the bread crumbs for the current request.
| 0.6
|-
| search_form
| Displays the find form for the current table.
| 0.6
|-
| language_selector
| Displays a menu to select the user&apos;s preferred language.
| 0.6
|-
| next_link
| Displays a link to the next XXX records.
| 0.6
|-
| prev_link
| Displays a link to the previous XXX records.
| 0.6
|-
| jump_menu
| Displays the select list of the records found in this found-set so that the user can jump directly to any record.
| 0.6
|-
| limit_field
| Displays a text field for the user to select the number of records to display per page.
| 0.6
|-
| result_index
| Displays the index of pages (1 to XXX) for this query.
| 0.6
|-
| summary_list
| Displays a list of records in the current found set using a summary format rather than the regular table format.
| 0.6
|-
| sort_controller
| Displays a control to sort the results on any column.
| 0.6
|-
| glance_list
| Displays a simple, brief list of records matching certain criteria.
| 0.6
|-
| record_view
| Loads structured data for a record as required for the view tab.
| 0.6
|-
| feed
| Generates a link to an RSS feed based on certain criteria.
| 0.6
|-
| translate
| Display a section of text in the user&apos;s selected language. (i18n).
| 0.6
|-
| if_allowed
| The contents of this block are shown only if the user has certain permissions.
| 0.6
|-
| editable
| Make a section of the page editable using AJAX.
| 0.6
|-
| abs
| Convert a URL into an absolute URL.
| 0.6
|}


===Useful Template Variables===

Xataface makes certain variables available to every template:

{| class=&quot;listing listing2&quot;
|-
! Name
! Description
! Version
|-
| $ENV.REQUEST
| Reference to the $_REQUEST array (HTTP Request parameters, both GET and POST)
| 0.6
|-
| $ENV.SESSION
| Reference to the $_SESSION array (the session variables)
| 0.6
|-
| $ENV.DATAFACE_PATH
| The file system path to the Xataface directory (i.e. the directory containing all of the Xataface files such as dataface-public-api.php).
| 0.6
|-
| $ENV.DATAFACE_URL
| The URL to the Xataface directory.
| 0.6
|-
| $ENV.DATAFACE_SITE_PATH
| The file system path to your application directory. (i.e. the directory containing your conf.ini and index.php files).
| 0.6
|-
| $ENV.DATAFACE_SITE_URL
| The URL to your application directory.
| 0.6
|-
| $ENV.DATAFACE_SITE_HREF
| The URL to your application&apos;s script.  This differs from the $ENV.DATAFACE_SITE_URL variable in that this also includes the script name.
| 0.6
|-
| $ENV.SCRIPT_NAME
| Same as $ENV.DATAFACE_SITE_HREF
| 0.6
|-
| $ENV.APPLICATION
| A reference to the application&apos;s conf array (i.e. the parsed contents of the conf.ini file).
| 0.6
|-
| $ENV.APPLICATION_OBJECT
| A reference to the Dataface_Application object for the application.
| 0.6
|-
| $ENV.SERVER
| A reference to the $_SERVER array.
| 0.6
|-
| $ENV.QUERY
| A reference to the current query (i.e.  Dataface_Application::getInstance()-&gt;getQuery())
| 0.6
|-
| $ENV.action
| The name of the current action as specified by the -action REQUEST parameter.
| 0.6
|-
| $ENV.table
| The name of the current table as specified by the -table REQUEST parameter.
| 0.6
|-
| $ENV.table_object
| A reference to the current table.
| 0.6
|-
| $ENV.relationship
| The name of the current relationship as specified by the -relationship REQUEST parameter.
| 0.6
|-
| $ENV.limit
| The value of the -limit REQUEST parameter.  This is the number of records to show per page.
| 0.6
|-
| $ENV.start
| The value of the -start REQUEST parmeter.  This is the starting point in the result set which is currently being displayed.
| 0.6
|-
| $ENV.resultSet
| A reference to the [http://dataface.weblite.ca/Dataface_QueryTool Dataface_QueryTool] object for this result set.
| 0.6
|-
| $ENV.record
| A reference to the [http://dataface.weblite.ca/Dataface_Record Dataface_Record] object that is matched by the current query.
| 0.6
|-
| $ENV.mode
| The name of the current mode.  e.g. find, list, browse
| 0.6
|-
| $ENV.language
| The 2-digit ISO language code that is currently selected as the user&apos;s preferred language.
| 0.6
|-
| $ENV.prefs
| A reference to the preferences array ($conf[&apos;_prefs&apos;])
| 0.6
|-
| $ENV.search
| The value of the current full-text search (i.e. the search that was entered into the upper right search field.
| 0.6
|}


==Smarty Plugins==

One of the most powerful features of [http://www.smarty.net Smarty] is its pluggable architecture.  You can easily add your own custom plugins to a registered &quot;plugins&quot; directory to add functions, modifiers, blocks, and other features to your templates.

Prior to Xataface 2.0, you Smarty plugins could only be placed in the  &apos;&apos;lib/Smarty/plugins&apos;&apos; directory of the Xataface distribution folder.  This is not very conducive to Xataface updates, though.  In general it is best practice to not change anything inside the xataface directory.  Most other configuration and extensions can be handled by making changes to your application&apos;s directory which override corresponding functionality in Xataface.

As of Xataface 2.0, you can create a directory named &apos;&apos;plugins&apos;&apos; to your application directory, Smarty knows to look in this directory for plugins.

For versions of Xataface prior to 2.0, you can make a small modification to the SkinTool to also add support as desribed in [http://xataface.com/forum/viewtopic.php?f=4&amp;t=6722 this post].

===Example Plugin===

The following is an example Smarty plugin adapted from [http://www.smarty.net/docs/en/plugins.functions.tpl this page] but modified slightly to work in Xataface.  It is a simple &quot;eightball&quot; plugin that adds a tag {eightball} to Xataface that you can use in any of your templates.  Whenever this tag is rendered it outputs one of a set of predefined strings randomly.

# Add a &apos;&apos;plugins&apos;&apos; directory to your application directory.  i.e.  &apos;&apos;path/to/app/plugins&apos;&apos;
# Add a file inside this &apos;&apos;plugins&apos;&apos; directory called &apos;&apos;&lt;nowiki&gt;function.eightball.php&lt;/nowiki&gt;&apos;&apos; with the following content:&lt;code&gt;
&lt;?php
/*
 * Smarty plugin
 * -------------------------------------------------------------
 * File:     function.eightball.php
 * Type:     function
 * Name:     eightball
 * Purpose:  outputs a random magic answer
 * -------------------------------------------------------------
 */
function smarty_function_eightball($params, Dataface_SkinTool $template)
{
    $answers = array(&apos;Yes&apos;,
                     &apos;No&apos;,
                     &apos;No way&apos;,
                     &apos;Outlook not so good&apos;,
                     &apos;Ask again soon&apos;,
                     &apos;Maybe in your reality&apos;);

    $result = array_rand($answers);
    return $answers[$result];
}
&lt;/code&gt;
# If you compare this function to the original example in [http://www.smarty.net/docs/en/plugins.functions.tpl the smarty tutorial] you&apos;ll notice that the 2nd parameter has been changed to type &apos;&apos;Dataface_SkinTool&apos;&apos; from &apos;&apos;Smarty_Internal_Template&apos;&apos;. If you don&apos;t make this change, you will get a fatal error when you try to use the tag.  This function defines an &apos;&apos;{eightball}&apos;&apos; tag that can be added to any Smarty template in Xataface.
# Next we&apos;ll create a template that uses this tag.  If your application doesn&apos;t have a &apos;&apos;templates&apos;&apos; directory, create one now (i.e. path/to/app/templates).
# Add a file inside your templates directory called &apos;&apos;testing.html&apos;&apos; with the following content:&lt;code&gt;
The eight ball says {eightball}
&lt;/code&gt;
# Now we need to display this template somewhere in our interface.  In this case, we&apos;ll choose the &apos;&apos;before_record_content&apos;&apos; block.  (This will render the template before the main section of the view tab).  Add the following method to your [[Application_Delegate_Class]]:&lt;code&gt;
function block__before_record_content(){
    df_display(array(), &apos;testing.html&apos;);
}
&lt;/code&gt;
# Now if you load your application in a web browser and navigate to the details view for a record, you should see something like the following:
&lt;nowiki&gt;&lt;img src=&quot;http://media.weblite.ca/files/photos/Screen_Shot_2012-04-16_at_12.33.01_PM.png?max_width=640&quot;/&gt;&lt;/nowiki&gt;

===See also:===

* [http://www.xataface.com/documentation/tutorial/getting_started/changing-look-and-feel Changing the Look &amp; Feel of Xataface] (From the Getting Started Tutorial)
* [http://www.xataface.com/documentation/tutorial/customizing-the-dataface-look-and-feel Cusomizing the Xataface Look &amp; Feel] Tutorial</content>
	<keywords>templates, plugins, smarty</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=44">
	<page_name>timestamp</page_name>
	<page_id>44</page_id>
	<page_title>timestamp</page_title>
	<content>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:

&lt;code&gt;
[date_created]
timestamp=insert
widget:type=hidden
&lt;/code&gt;

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===

* &apos;&apos;&apos;update&apos;&apos;&apos; - Causes timestamp to be updated whenever the record is modified.
* &apos;&apos;&apos;insert&apos;&apos;&apos; - Causes the timestamp to be updated only when the record is first inserted.</content>
	<keywords>timestamp, date, datetime</keywords>
	<language>en</language>
	<original_page>0</original_page>
</wiki>
<wiki id="wiki?page_id=110">
	<page_name>Contribute_to_Xataface_Translation_Project</page_name>
	<page_id>110</page_id>
	<page_title>How to Contribute Translations</page_title>
	<content>[[toc]]

==Synopsis==

Xataface stores its translations in INI files in its lang directory, one for each language.  You can develop your own translation by first copying the en.ini file to xx.ini (where xx is the ISO language code for the language you are translating for), then modifying the translations into your target language. &apos;&apos;&apos;NOTE: THIS IS NOT THE PREFERRED WAY TO CONTRIBUTE TRANSLATIONS.  PLEASE SEE &quot;Adding Translations Using Google Spreadsheets&quot; BELOW&apos;&apos;&apos;.

==Anatomy of a Language .INI file==

The language .INI files (e.g. en.ini, es.ini, etc...) consist of key-value pairs, where the key is a unique identifier for a string in Xataface, and the value is the translation.  All language files should contain the same keys, however if you omit a key from your translation, Xataface will just fall back to the default value that is defined in the PHP source code.

===Example Snippet from en.ini file===

&lt;code&gt;
scripts.GLOBAL.FORMS.OPTION_PLEASE_SELECT = &quot;Please Select ...&quot;
save_button_label = &quot;Save&quot;
scripts.GLOBAL.MESSAGE.PERMISSION_DENIED = &quot;Permission Denied&quot;
scripts.GLOBAL.NO_RECORDS_MATCHED_REQUEST = &quot;No records matched your request.&quot;
&lt;/code&gt;

In this small segment you can see 4 strings that are translated.  The values on the left of the equals sign are the keys.  Their corresponding values are on the right of the equals signs.  A corresponding segment of the fr.ini (French) language file looks like:

&lt;code&gt;
scripts.GLOBAL.FORMS.OPTION_PLEASE_SELECT = &quot;SVP sélectionnez ...&quot;
save_button_label = &quot;Enregistrer&quot;
scripts.GLOBAL.MESSAGE.PERMISSION_DENIED = &quot;Permission Refusée&quot;
scripts.GLOBAL.NO_RECORDS_MATCHED_REQUEST = &quot;Aucun résultat ne correspond à votre requête.&quot;
&lt;/code&gt;

You can see that the keys (the values on the left) are identical to those in the en.ini snippet.  Only the values are changed (translated) into French.

&apos;&apos;&apos;NOTE: IT IS BETTER TO USE GOOGLE SPREADSHEETS TO EDIT TRANSLATIONS, THAN TO WORK WITH INI FILES DIRECTLY. PLEASE SEE &quot;Adding Translations Using Google Spreadsheets&quot; BELOW&apos;&apos;&apos;


==Gotchas: Things to watch out for==

When editing or adding translations in INI files, you need to be aware of a few gotchas related to how INI files work.  If you mess up a line by forgetting to add a quote, you could cause a parse error which would cause Xataface to ignore the language file altogether.  The following are a few common pitfalls:

===Use UTF-8 Encoding===

All ini files should use UTF-8 encoding, so make sure you are using a text editor that supports UTF-8 if you want to edit INI files.  (But it is better to just use Google Spreadsheets for the editing if possible, in which case you don&apos;t have to worry about this).

===Wrap Translations in Double Quotes===

All translations should be wrapped in double quotes.  E.g.
&lt;code&gt;
mykey=&quot;My Value&quot;
&lt;/code&gt;

If you forget to close a quote, it will likely cause a parse error and Xataface will fail to load the file.  E.g.
&lt;code&gt;
mykey=&quot;My Value
&lt;/code&gt;
would be a problem.


===Can&apos;t Use Double Quotes as Part of the Translation===

Since INI files use double quotes to wrap strings, you can&apos;t use a double quote inside your translation.  E.g. you can&apos;t do this:
&lt;code&gt;
mylink=&quot;&lt;a href=&quot;http://google.com&quot;&gt;Google&lt;/a&gt;&quot;
&lt;/code&gt;
because of the inline double quotes.

One way around this is to try to use single quotes where possible.  E.g.
&lt;code&gt;
mylink=&quot;&lt;a href=&apos;http://google.com&apos;&gt;Google&lt;/a&gt;&quot;
&lt;/code&gt;

Another way around this is to the &apos;&apos;&quot;_Q&quot;&apos;&apos; key sequence, which Xataface will
automatically convert to a double quote for you at runtime.  E.g. You could do:
&lt;code&gt;
mylink=&quot;&lt;a href=&quot;_Q&quot;http://google.com&quot;_Q&quot;&gt;Google&lt;/a&gt;&quot;
&lt;/code&gt;

&apos;&apos;&apos;NOTE: If you use Google Spreadsheets to edit your translations, you won&apos;t have this problem.  You can use double quotes inside your translations.  The [[csv2ini]] tool will automatically convert these to an appropriate form when the spreadsheet is converted to the INI files.&apos;&apos;&apos;


===Leave Variables Alone===

Some translated strings include variables that are meant to be replaced by Xataface at runtime.  These should be left intact across translations.  You can identify a variable by their resemblance to PHP variables (prefixed with a $).

E.g. In the en.ini file, the translation:
&lt;code&gt;
No action found = &quot;No action found named &apos;$name&apos;&quot;
&lt;/code&gt;
has the variable &apos;&apos;$name&apos;&apos;.

So the French translation should maintain this variable.  E.g. in the fr.ini file:
&lt;code&gt;
No action found = &quot;Aucune action nommée &apos;$name&apos;&quot;
&lt;/code&gt;


==Adding Translations Using Google Spreadsheets==

In order to help keep translations more up to date, we have developed a set of tools to enable us to use Google Spreadsheets to edit and add translations, and convert these spreadsheets on demand into an appropriate set of language INI files.

The spreadsheet containing the Xataface translations is public to view and is located  [https://spreadsheets.google.com/ccc?key=0AqJNZUI7flxSdFVLWDlnVVpQZ3dMaGZhVjVHN2c3bEE&amp;hl=en here].  If you would like to add your own translations or modify existing translations, please contact [mailto:steve@weblite.ca Steve Hannah] so that you can be given editor permission.  You will first need a google docs account, then we can give you permission to edit the spreadsheet.

This centralized spreadsheet is converted to INI files and merged into SVN before every release.  You can also export this spreadsheet as a CSV and convert it to Xataface&apos;s language INI files yourself using the [[csv2ini]] tool that is located in the tools directory of the Xataface distribution.


===Gotchas with Google Spreadsheets===

Editing translations with Google Spreadsheets is much safer than editing the INI files directly.  You don&apos;t have to worry about encoding issues, and you don&apos;t have to dance around double quotes like you do with INI files.  There is only one known thing to watch out for:

====Starting a translation with a Single Quote====

If you start a translation with a single quote, Google Spreadsheets will interpret this as a directive to indicate that the contents of that cell should be considered a string (and not a number for example).  E.g. If you enter the following into a Google Spreadsheets cell:
&lt;code&gt;
&apos;Help!&apos;, I exclaimed
&lt;/code&gt;
If you unfocus from that cell it will only say:
&lt;code&gt;
Help!&apos;, I exclaimed
&lt;/code&gt;
If you go back into edit mode of the cell again, you&apos;ll see your opening single quote again... and when you tab out, it will disappear again.  

You can work around this issue by just using two single-quotes for the first quote.  E.g.:
&lt;code&gt;
&apos;&apos;Help!&apos;, I exclaimed
&lt;/code&gt;

This way Google will interpret the first quote as a directive, and it will use the second one as an actual single quote.


====Converting the Google Translation Spreadsheet into INI Files====

So you&apos;ve contributed a number of translations to the [https://spreadsheets.google.com/ccc?key=0AqJNZUI7flxSdFVLWDlnVVpQZ3dMaGZhVjVHN2c3bEE&amp;hl=en Xataface Translations Google Spreadsheet], and you want to be able to use them in your installation of Xataface before the next release.  Just follow the steps below:

# Download the spreadsheet as a CSV file, using the &apos;&apos;File&apos;&apos; &gt; &apos;&apos;Download as&apos;&apos; &gt; &apos;&apos;CSV (Current Sheet)&apos;&apos; menu item in Google Spreadsheets.
# Run the [[csv2ini]] PHP script located in the xataface/tools directory to convert the xataface-translations.csv file that you downloaded from Google Spreadsheets in the previous step into INI files.  The conversion command looks like:
&lt;code&gt;
$ php /path/to/xataface/tools/csv2ini.php /path/to/xataface-translations.csv /path/to/destination/dir/
&lt;/code&gt;

This will convert the xataface-translations.csv file into a set of language INI files and place them the specified destination directory  (don&apos;t forget the trailing slash) on /destination/dir so that the script knows its a directory.  You can then copy these INI files into your xataface/lang directory to make them live.

&apos;&apos;&apos;Note: the [[csv2ini]] script has only been used in a unix/os x type environment.  Some small modifications would probably be necessary to make them work on Windows.&apos;&apos;&apos;




</content>
	<keywords>Translations, Google Spreadsheets, en.ini, fr.ini</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki>
<wiki id="wiki?page_id=109">
	<page_name>beforeSave</page_name>
	<page_id>109</page_id>
	<page_title>beforeSave Trigger</page_title>
	<content>Back to [[Delegate class methods]]

[[toc]]



===Synopsis===

The beforeSave trigger can be implemented in any table&apos;s [[delegate class|Delegate Class Methods]] to perform functionality that should be run *before* a record of that table is saved.  This is a useful place to insert additional field values depending on the input of the save record form.

This method is called both when records are inserted and when existing records are updated.  Some other triggers include [[beforeInsert]], [[beforeUpdate]], [[afterSave]], [[afterInsert]], and [[afterUpdate]], which do what you might expect.


===Method Signature===

&lt;code&gt;function beforeSave( Dataface_Record $record);&lt;/code&gt;

====Parameters====

# &apos;&apos;&apos;$record&apos;&apos;&apos; - The record that is about to be saved.  This is a [http://dataface.weblite.ca/Dataface_Record Dataface_Record] object.

====Returns====

# [http://dataface.weblite.ca/Dataface_Error Dataface_Error] on failure (if you want to cancel the save).


===Examples===

Given a table named &quot;people&quot;, suppose we wanted to automatically populate a field named &quot;full_name&quot;  with the concatenation of the &quot;first_name&quot; and &quot;last_name&quot; fields.  (Note you could also achieve a similar thing by making a calculated field for &quot;full_name&quot;, but for this example, we assume that we actually want to store this in the database.

We create a beforeSave() trigger that automatically updates the &quot;full_name&quot; field every time the record is saved.

In the &quot;people&quot; table delegate class (i.e. tables/people/people.php)
&lt;code&gt;
class tables_people {
    function beforeSave($record){
        $record-&gt;setValue(&apos;full_name&apos;, 
            $record-&gt;val(&apos;first_name&apos;).&apos; &apos;.$record-&gt;val(&apos;last_name&apos;)
        );
    }
}
&lt;/code&gt;

==See Also==

* [http://www.xataface.com/documentation/tutorial/getting_started/triggers Triggers section of the Xataface Getting Started Tutorial]
</content>
	<keywords>triggers, beforeSave,</keywords>
	<language>en</language>
	<original_page></original_page>
</wiki></record>