A place to discuss and receive support for the Library DB application.
by trevor » Fri Feb 15, 2008 6:44 am
I am new to Xataface (and especially so to quickforms), and would like to provide the following entry form for all users, whether logged in or not;
a) Text link on welcome page that activates a simple feedback form (prompts are first/last name, email, type of feedback via enum, feedback text) that is integrated into library DB as per the Find form.
b) Entries to be validated and saved to a 'Submissions' table, which also is to have non prompted for admin fields ie 'actioned' (enum y/n) and 'actioneddate' (datetime)
c) The submissions table not to have any visible presence (ie tabs) on the page, and to retain the existing audience menu structure
d) Validation of email entry on submit, with save to database and confirmatory message page to user on successful save plus email to site administrator of new record details.
I have followed the 'How to build submission forms using Xataface' tutorial (ie set up the table, ini files and permissions etc), but don't know how to get it to smoothly integrate into the application without extra tabs and/or loss of the 'audiences' menu on the left of the page.
Some sample snippets of code would be appreciated.
Trevor
-
trevor
-
- Posts: 7
- Joined: Thu Feb 14, 2008 7:56 am
- Location: London
by shannah » Fri Feb 15, 2008 10:26 am
Hi Trevor,
There are a few ways you could try to accomplish this. In all cases, you'll start by creating your submissions table in the database.
You can then go about integrating this table.
The easiest way to do this is to just link directly to the new record form for this table.
e.g. index.php?-table=submissions&-action=new
There are a couple of stipulations you want to make though since it is a submission form:
1. Non admin users can only add new records to the table (not edit existing ones).
http://xataface.com/documentation/tutor ... ermissions
2. Non admin users don't see the tabs etc.. in the UI.
(see http://xataface.com/documentation/tutor ... g_features)
For (2) above, you'll need to make a small departure from the code example in the tutorial because you want the tabs to disappear only for this table.
In library DB the default application has a getPreferences() method (in the conf/ApplicationDelegate.php class) as follows:
- Code: Select all
function getPreferences(){ if (!isAdmin()){ return array( 'show_table_tabs'=>0, 'show_record_tabs'=>0, 'show_tables_menu'=>0 ); } return array(); }
So the tabs etc are already hidden. If you want to hide more things for the submissions table you can have it return different preferences in that case: - Code: Select all
function getPreferences(){ $app =& Dataface_Application::getInstance(); $query =& $app->getQuery(); if ( !isAdmin() ){ if ( $query['-table'] == 'submissions'){ return array( 'show_result_stats'=>0, 'show_jump_menu'=>0, 'show_result_controller'=>0, 'show_table_tabs'=>0, 'show_actions_menu'=>0, 'show_tables_menu'=>0, 'show_search'=>0, 'show_record_actions'=>0, 'show_recent_records_menu'=>0, 'show_record_tabs'=>0, 'show_record_tree'=>0, 'show_bread_crumbs'=>0); } else { return array( 'show_table_tabs'=>0, 'show_record_tabs'=>0, 'show_tables_menu'=>0 ); } } return array(); }
For your custom success page, you need to tell xataface to forward to the success page after the new action is completed. http://xataface.com/documentation/tutor ... ucess_pageTo create your custom success page, you could just create a custom action. e.g. Create a template for your action: create a file named 'success.html' and add it to your templates directory. Then add the following to the actions.ini file to register the action: - Code: Select all
[success] template=success.html [/success]
Your template (success.html) might look something like this: - Code: Select all
You have successfully saved the form
Note that that page would just be a plain which page with only your text. If you want it to appear inside the normal application template you would do: - Code: Select all
{use_macro file="Dataface_Main_Template.html"} {fill_slot name="main_column"} You have successfully saved the form. {/fill_slot} {/use_macro}
Note that your success page would be available at index.php?-action=success --------- ALTERNATIVE APPROACH -------------- The procedure described above leverages the framework as much as possible. If you want more control over your submission form you may want to create a custom action and tap directly into the api to create your forms: 1. We will add a custom action named 'submissionform' to the application: Create a file named 'submissionform.php' and add it to your actions folder. It will contain the following contents: - Code: Select all
class actions_submissionform { function handle(&$params){ // .... This is where you put your code for your action. } }
An action is kind of like your own PHP script. You can do whatever you want with this action. We are going to use the xataface api to create a new record form. the df_create_new_record_form function will create a "new" record form on a particular table. It takes the table name, and optionally an array of field names to be included on the form. e.g. - Code: Select all
$form =& df_create_new_record_form('submissions', array('firstname','lastname','email'));
if ( $form->validate() ){ $res =& $form->process(array(&$form,'save'), true); // process the form - save to database if ( $res && !PEAR::isError($res) ){ header("Location: index.php?-action=success"); // forward to your custom success page if all went well. exit; } header("Location: index.php?-action=failed"); // forward to a custom failed page exit;
}
$form->display();
There are other strategies also. Pick one and then work from there. Both can be customized completely... just take it step by step.
-Steve
-
shannah
-
- Posts: 4457
- Joined: Wed Dec 31, 1969 5:00 pm
by trevor » Fri Feb 15, 2008 1:15 pm
Thanks Steve
Almost there, but still a few issues. I will include all the relevant code below in case you can spot where I'm going wrong (permissions and/or links?) as well as help the others out there with the same predicament.
a) linked to form via
index.php?-table=submissions&-action=new
b) Permissions set as follows (submissions.php);
function getPermissions(&$record){ $app =& Dataface_Application::getInstance(); $query =& $app->getQuery(); if ( $query['-action'] == 'new'){ return Dataface_PermissionsTool::ALL(); } else { return Dataface_PermissionsTool::NO_ACCESS(); } }
c) preferences set as follows;
function getPreferences(){ if (!isAdmin()){ return array( 'show_table_tabs'=>0, 'show_record_tabs'=>0, 'show_tables_menu'=>0 ); } return array(); }
d) Clicked on the link and submissions form displayed, but following issues
i) completely missing the left menu area (is this menu controlled by the -table setting?)
ii) No email address validation type (ie want something like widget:type = email)
iii) If they are already logged in I would like a 'registeredusername'
field to be pre-populated if possible with their current id
iv) Name of table 'submissions' appears in box around form. As I already
have set a title to the page, how do I hide this boxed table name (top left).
e)When I click the submit button I get the following error message after a 'Record successfully saved' message (and I checked the db to cfm the save).
Permission to perform action 'edit' denied. Requires permission 'edit' but only granted '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0'
This error message was immediately followed by the header text Permission Denied
Relevant settings
actions.ini
[success]
template=success.html
[/success]
success.html
{use_macro file="Dataface_Main_Template.html"}
{fill_slot name="main_column"}
Your Submission was successfull
Thank you for your submission and we will be responding to you shortly.
{/fill_slot}
{/use_macro}
submissions.php
function after_action_new(){
$auth =& Dataface_AuthenticationTool::getInstance();
$user =& $auth->getLoggedInUser();
if ( !$user ){
// The user is not logged in so we forward to a success page.
header('Location: index.php?-action=success');
exit;
}
}
Trevor
-
trevor
-
- Posts: 7
- Joined: Thu Feb 14, 2008 7:56 am
- Location: London
by shannah » Fri Feb 15, 2008 4:21 pm
Hi Trevor,
You're getting really close.
completely missing the left menu area (is this menu controlled by the -table setting?)
Good point. Currently only the books table has been set up for the menu. You can expand this so that the menu appears in all tables by moving the block__before_application_menu() method from the tables/books/books.php file (i.e. the books delegate class) to the conf/ApplicationDelegate.php file (i.e. the Application Delegate class). No email address validation type (ie want something like widget:type = email)
Use validators:email=1. See Example 3 at http://framework.weblite.ca/documentati ... validationIf they are already logged in I would like a 'registeredusername' field to be pre-populated if possible with their current id
Use the beforeInsert trigger in the submissions delegate class. e.g. - Code: Select all
function beforeInsert(&$record){ $auth =& Dataface_AuthenticationTool::getInstance(); $user =& $auth->getLoggedInUser(); if ( $user ){ $record->setValue('registeredusername', $user->val('username')); } }
Name of table 'submissions' appears in box around form. As I already have set a title to the page, how do I hide this boxed table name (top left)
Good point. Use stylesheets to try to hide this stuff for now... I don't think there's a config option to prevent this. I don't have any 0.7.1 installs readily available for me to look at to see what the stylesheet directives would be but you can figure out something that will work by just looking at the HTML source code (i.e. View source in the browser). When I click the submit button I get the following error message after a 'Record successfully saved' message (and I checked the db to cfm the save). Permission to perform action 'edit' denied. Requires permission 'edit' but only granted '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0' This error message was immediately followed by the header text Permission Denied
This likely means that the record was saved ok, but then after saving it sends the user to the edit form for the same record - and the user doesn't have permission to edit - only create new.
That is what the after_action_new trigger is for. See
http://xataface.com/documentation/tutor ... ucess_page
for information on how to forward the user to a success page instead of the edit form.
Best regards
Steve
-
shannah
-
- Posts: 4457
- Joined: Wed Dec 31, 1969 5:00 pm
by trevor » Sat Feb 16, 2008 4:24 am
Very many thanks Steve,
Now very very close, but not quite there yet
a) Menu now appears correctly in all tables
b) Email validators
I am developing on a windows environment, so email validation doesn't work as
the 'checkdnsrr' function is not implemented on the Windows platforms. I get
the following warning message (top of page) with an invalid email message by the email prompt;
Warning: preg_match() [function.preg-match]: Empty regular expression in C:\inet\CSAF\dataface\lib\HTML\QuickForm\Rule\Regex.php on line 61
Hopefully when I upload to my online host all will be well.
c) Have added the beforeInsert trigger code
i) This code only inserts data on writing to the database
ii) It does not pre-populate the 'registeredusername' prompt. Basically
I am looking for a mechanism that enables one to set a dynamic
default value on the form. (a beforeDisplay type trigger)
c) To hide the 'submissions' label in the box around the form I adjusted the css by adding 'display: none;' as follows;
legend { background: White; padding: 0.5em; font-size: 90%; display: none; }
d) after_action_new trigger
I had already implemented this (see my second posting above). The problem was
that I was a logged in user, so the redirection wasn't being implemented. As
all menu options now appear correctly on all pages (point a above), I just
simply removed the $user check to ensure redirection always occurs to the
success page.
Only point now o/s is a mechanism to preset defaults on the form. As a side
issue to default setting, I do have the following queries with the Find form;
1) If a user does a search (via find), and discovers that the number of records
is vast (my database has over 90000 records and growing), how do I prefill the
the find boxes with their previous search values so that they can easily refine
their criteria. I have stored the find entries in the ENV array variable, so just
need to know how to pre-populate the individual search prompts with these values.
2) One of the prompts is the year of publication. How do I ensure that any entry
is exactly a four digit integer within a specified range (upper limit being the
current year)?
3) Another potential search prompt is a table column which has a choice of two enum
values (say 'A' and 'B'). I would like the search to optionally ignore this, effectively
allowing the user to choose either 'All' (default), 'A' or 'B' and not just 'A' or 'B'.
How does one achieve this, noting the need to reset the default value to its previous setting
if the page is reloaded (a clear all settings button would be a nice feature too, but miracles can wait)?
Just love the depth of functionality available
Trevor
-
trevor
-
- Posts: 7
- Joined: Thu Feb 14, 2008 7:56 am
- Location: London
by shannah » Sat Feb 16, 2008 1:48 pm
am looking for a mechanism that enables one to set a dynamic default value on the form. (a beforeDisplay type trigger)
See http://xataface.com/forum/viewtopic.php?t=3936#19687c) To hide the 'submissions' label in the box around the form I adjusted the css by adding 'display: none;' as follows; legend { background: White; padding: 0.5em; font-size: 90%; display: none; }
This is good. However it will hide *all* fieldset legends, not just this one, which is probably not exactly what you want. Better to find a way to qualify the legend. e.g. - Code: Select all
.Submissions-table-div legend { display:none; }
Note that I made up the .Submissions-table-div class.. check the HTML code to find an appriate element that you can use to qualify the legend tag. how do I prefill the find boxes with their previous search values
Clicking on the 'find' tab will automatically retain the current search settings. Can't think of an easy (i.e. 2 lines or less) way to override the default values of the search to something different than the current criteria. One of the prompts is the year of publication. How do I ensure that any entry is exactly a four digit integer within a specified range (upper limit being the current year)?
Use validators:regex : http://framework.weblite.ca/documentati ... validation(Example 2). Your regex would be: - Code: Select all
validators:regex = "/[0-9]{4}/"
Another potential search prompt is a table column which has a choice of two enum values (say 'A' and 'B').
Will this search prompt correspond to a column in the books table, or will it cause it to search different tables?
If it is a column in the search table, you could achieve this simply with an enum() field in the books table with the 2 values you specified. The search form would automatically give the user a select list to select A or B (or none - which would just return all possible values).
Best regards
Steve
-
shannah
-
- Posts: 4457
- Joined: Wed Dec 31, 1969 5:00 pm
by trevor » Sat Feb 16, 2008 2:40 pm
Steve,
All sounds good, but too late in the evening to do anything further tonight here in London. I also don't think I was clear enough on the resetting of the search criteria to allow user refinement.
Specific example from the online demo;
Click 'Search books', and enter Title='a' and ISBN='0' (zero). The query returns 318 records.
I decide this is too many records to browse through, so immediately click 'Search books' again, hoping to see Title pre-populated with 'a', and ISBN with '0' - but both are blank.
The requirement is therefore to be able to pre-populate all prompt boxes with their previous search settings so enabling the user to easily fine tune the criteria and thus reduce the number of returned records to a manageable size.
One last 'new' query (or is it best to start a new thread when the topic content changes - let me know?) - The Display Records per page box accepts numeric input. I would prefer to only allow users to select the number from a drop down list (say 25, 50, 75 and 100) to ensure that they don't enter a large silly number and time out or crash whilst waiting (motto - protect the users from themselves).
Many thanks for your time and effort to date - much appreciated.
Trevor
-
trevor
-
- Posts: 7
- Joined: Thu Feb 14, 2008 7:56 am
- Location: London
by shannah » Sat Feb 16, 2008 7:07 pm
The requirement is therefore to be able to pre-populate all prompt boxes with their previous search settings
Oh yes... the default "find" tab in dataface applications works this way, but the "Search Books" link in the menu is more or less a static link in the audience_menu template. You can change it to work this way by changing the link to the search page in the audience_menu.html template from: - Code: Select all
{$ENV.DATAFACE_SITE_HREF}?-table=books&-action=find
to - Code: Select all
{$ENV.APPLICATION_OBJECT->url('-action=find')}&-table=books
One last 'new' query (or is it best to start a new thread when the topic content changes - let me know?) - The Display Records per page box accepts numeric input. I would prefer to only allow users to select the number from a drop down list (say 25, 50, 75 and 100) to ensure that they don't enter a large silly number and time out or crash whilst waiting (motto - protect the users from themselves).
It isn't easy to change this to a select menu, however this box just manipulates the '-limit' GET variable, so you can put your own constraints on this at the beginning of the index.php file. e.g. - Code: Select all
if ( !$_POST and @$_REQUEST['-limit'] and $_REQUEST['-limit'] > 100 ){ $_GET['-limit'] = $_REQUEST['-limit'] = 100; }
This code checks to make sure that no POST variables are set (we don't really want to mess with post requests, then it checks if the limit is greater than 100... if so, it just sets the limit to 100.
-
shannah
-
- Posts: 4457
- Joined: Wed Dec 31, 1969 5:00 pm
by trevor » Sun Feb 17, 2008 3:37 pm
Steve,
Find now displays previously entered entries correctly (exactly as required - thanks), though the validation on the year doesn't work?
a) year ini file setting (single or double quotes give same result)
validators:regex = "/[0-9]{4}/" validators:regex:message = "Year must be a four digit number"
I entered in 'abcd' to the year prompt and pressed 'Find' - it doesn't display any error message on the find page but simply shows an empty result list with a 'No records matched your request.' message. Setting regex to 'numeric' (without the quotes) also produces exactly this same result! I expected the find page to be retained with the specified error message displayed against the year prompt!
b) Enums on the 'A', 'B' column
I find the addition of the radio buttons on enum fields very confusing (and so would my potential users). If I select 'None' then regardless of my selection of 'A' or 'B' (or not selecting either), no records are displayed (as all values must be one or the other, no matches would be the expected result anyway). If there were NO radio buttons then the result would be exactly as required (holding the shift key down enables one to select both values, which is the same as OR). Therefore,
i) How do I hide the radio buttons (will look at the css shortly)?
ii) How do I control the depth of the drop down box - it allows for four values, and I only want space for the two characters?
Regarding the limiting of the drop down list box for setting the number of displayed rows, you need to be aware that the entering of certain values can cause the application to crash! If you put in a zero or a non numeric value (ie 'xx')
Found nn of 380 records in table books Now Showing 1 to 0 (Display 0 Records per page)
Fatal error: Maximum execution time of 30 seconds exceeded in /home/weblite_ca/lamp/dataface-0.6/Dataface/LinkTool.php on line 89
The script for limiting the user entry therefore needs to be much more robust,
catering (by default) for both a lower limit as well as a non numeric entry!!
Perhaps something like the following (not tested yet, nor efficient - purely to illustrate the respective elements) ;
if ( !$_POST and @$_REQUEST['-limit'] and $_REQUEST['-limit'] > 100 ){ $_GET['-limit'] = $_REQUEST['-limit'] = 100; elseif ( !$_POST and @$_REQUEST['-limit'] and $_REQUEST['-limit'] < 1 ){ $_GET['-limit'] = $_REQUEST['-limit'] = 25; elseif ( !$_POST and @$_REQUEST['-limit'] and !ctype_digit($_REQUEST['-limit']) ){ $_GET['-limit'] = $_REQUEST['-limit'] = 25; }
I have also noticed the following problem areas;
1) potential security error with the demo app (not using the profile feature, so only notifying you of it for informational purposes)
a) Profile page enabled
b) login (guest/guest)
c) Click on My Profile
d) Found states '1 or 3 records in table users', though only one entry in listbox
e) Enter 'a' in the search box, and you can see all three users ('admin', 'guest' and 'admin' again)
f) Click on any of the three users and you can see the details of that user!!
Likely a simple matter to adjust security to prohibit this, but some current installations might not be aware of this out of the box default setting.
2) widget:label text
I added multiple names to the database, and wanted to reference them by their numbers - added in (2) to one label's text, and (3) to the other (and visibility:find=hidden set on both of them). This caused all explicitly hidden fields to be displayed in the list! - had to put the whole label text in single quotes to achieve what was wanted.
Trevor
-
trevor
-
- Posts: 7
- Joined: Thu Feb 14, 2008 7:56 am
- Location: London
by shannah » Sun Feb 17, 2008 9:41 pm
I entered in 'abcd' to the year prompt and pressed 'Find' - it doesn't display any error message on the find page
Sorry, didn't understand that you wanted this validation on the find page. validators:xxxx is for the edit forms. I suppose the best way to do what you want to do is create a valuelist called years with all the available years, and then set this vocabulary on the year field. e.g. valuelists.ini: - Code: Select all
[years] 1987=1987 1988=1988 ... 2008=2008
In the fields.ini find the 'year' field section and set: vocabulary=years find the addition of the radio buttons on enum fields very confusing (and so would my potential users). If I select 'None' then regardless of my selection of 'A' or 'B' (or not selecting either)
Clicking the "None" radio button will return the inverse of the search. I.e. normally not selecting any values will return records with any value. If you then select "None", it will return records that don't contain a value in this field (i.e. only null fields). Similarly if you select 'A', it only returns records with 'A' in this field. If you then select "None" it returns only records that don't havce 'A' in this field. To remove the radio buttons, try css. Perhaps something like the following (not tested yet, nor efficient - purely to illustrate the respective elements) ;
your solution looks like a good one. potential security error with the demo app...
Thanks I'll add it to the issue tracker. I added multiple names to the database, and wanted to reference them by their numbers - added in (2) to one label's text, and (3) to the other (and visibility:find=hidden set on both of them). This caused all explicitly hidden fields to be displayed in the list! - had to put the whole label text in single quotes to achieve what was wanted.
Likely the parenthesis caused problems with the INI parser. If you are using any special characters in the INI file values you pretty much need to use quotes (as you discovered).
-
shannah
-
- Posts: 4457
- Joined: Wed Dec 31, 1969 5:00 pm
by trevor » Mon Feb 18, 2008 5:36 am
Steve,
a) Using a valuelist for year selection is a non starter, as there would be over 100 entries (and the upper limit is governed by the current year value ie currently 2008). Have fudged the issue by setting a warning message on the list page when the year value is non numeric outside of the designated range. It's not pretty (but effectual), so would prefer some validation if possible pre the submission to the list process.
b) By default the AND, OR and NONE settings can't be controlled by css, as hiding them won't hide the associated entries, so mucking up the spacing. Have therefore simply commented out the relevant lines in the source code - no issue as no other enum selections envisaged.
c) Have put the following code in my index.php
if ( !$_POST and @$_REQUEST['-limit']){ if ($_REQUEST['-limit'] > 100 ) $_GET['-limit'] = $_REQUEST['-limit'] = 100; if ($_REQUEST['-limit'] < 10 ) $_GET['-limit'] = $_REQUEST['-limit'] = 25; }
This fixes the majority of entries (including non numerics), but has some deficiencies and side effects
1) Entering in a single zero doesn't work as you get a display of zero records ('Now showing 1 to 0'), though entering in '00' does work (resetting to 25)! It's as if a single zero is treated as a special case internally. Note that the app errors (as stated before) if a single zero is entered without the above code!?
2) Deleting the show number so it's empty (or spaces) seems to default to 100 rows, though the 'Now Showing' range is displayed as '1 to 0'.
3) If I select another audience, the entered value reverts back to the default row number of 30 (as there is no '-limit=##' entry in the page url. I would like the limit, once over-ridden, to be retained for the whole of the current session (unless the user manually changes it to yet another number). Is this possible, and if so what is the most appropriate method (I think the most likely will be via a new global variable?) and code placement.
Trevor
-
trevor
-
- Posts: 7
- Joined: Thu Feb 14, 2008 7:56 am
- Location: London
by shannah » Tue Feb 19, 2008 1:03 pm
would prefer some validation if possible pre the submission to the list process.
You can always continue down the same route you took for validating the -limit parameter. E.g. add code to the beginning of your index.php file. It would be a little more complex but not unfeasible. Entering in a single zero doesn't work as you get a display of zero records
That is because when $_REQUEST['-limit'] is zero, @$_REQUEST['-limit'] will evaluate to false. Because in PHP 0 == false == ''. You can fix this by changing - Code: Select all
if ( !$_POST and @$_REQUEST['-limit']){
to - Code: Select all
if ( !$_POST and isset($_REQUEST['-limit']){
If I select another audience, the entered value reverts back to the default row number of 30
You could use a cookie to track this value.
See http://php.net/set_cookie
-Steve
-
shannah
-
- Posts: 4457
- Joined: Wed Dec 31, 1969 5:00 pm
by trevor » Wed Feb 20, 2008 4:03 am
Steve,
Except for the numeric validation on the year I think I'm now there - a very robust and professional looking application thanks to Xataface and your fantastic support
A few notes
a) Following code you quoted was missing an extra close bracket
- Code: Select all
if ( !$_POST and isset($_REQUEST['-limit'])){
b) To implement cookies required only three small mods, and it works as required (on my windows pc anyway) i) index.php code - Code: Select all
if (!isset($_COOKIE["PageRows"])) { // first time use, so set to site default value setcookie("PageRows", 25); }
and ... - Code: Select all
if ( !$_POST and isset($_REQUEST['-limit'])){ ... setcookie("PageRows", $_REQUEST['-limit']); }
ii) Application.php code change - Code: Select all
if ( !isset($this->_conf['default_limit']) ){ $this->_conf['default_limit'] = $_COOKIE["PageRows"]; }
iii) conf.ini - removed default limit setting - Code: Select all
;default_limit=25
Again, very many thanks
Trevor
ps Getting the full code (second part of point 'i') to display correctly has been a real pain, as it is garbled when previewed - had to resort to ... in the end to get it to display correctly!
-
trevor
-
- Posts: 7
- Joined: Thu Feb 14, 2008 7:56 am
- Location: London
Return to Library DB Discussion
Who is online
Users browsing this forum: No registered users and 0 guests
|