Chapter 3
Preface
In this chapter, I will present how to:
- use the DBLJSLCField
- use the DBLIntegerField
- perform custom checks of the posted data
We will create a table to hold car model information:
- Unique ID
- Name
- Maker (brand)
- First year of the model
- Last year of the model
EXAMPLE: You can find fully working code for this task is contained in the
EXAMPLE/admin/model where it is used to edit the model table.
Header file
Again, header file is the most interesting: Include definitions (here we show
what really is in the example - including global definitions and including
DBLIB classes from path set in a global variable):
<?
require('../../global.php');
require_once("$DBLIB_PATH/DBLMYSQLQuery.php");
require_once("$DBLIB_PATH/DBLView.php");
require_once("$DBLIB_PATH/DBLTextField.php");
require_once("$DBLIB_PATH/DBLJSLCField.php");
require_once("$DBLIB_PATH/DBLIntegerField.php");
require_once("$DBLIB_PATH/DBLLabelField.php");
Now we will instantiate the view:
$view =& new DBLView("model");
Now we will define fields we use in the view. First will be the name field:
// Name
$view->addField($name =& new DBLTextField("name","Name","",32,30));
$name->allowEmpty = false;
$name->dbName = "model.name";
$name->filterSize = 20;
The field may not be empty and will have only 20 characters in the filter.
dbName is set to tableName.fieldName. It is necessary for
the filter to work, since there will be actually two name columns
in the select. See discussion in index.php for closer explanation.
Next we will define the brand field. User will select the brand from
a list of defined brands. However, we suppose we will have many brands, so
that selection using combo box would not be convenient. So we will use DBLJSLCField.
It works much like the DBLLCField, but the value of the field is selected
in another (popup) window, brought up by clicking on a button. As the name
suggests, this field requires JavaScript to work. First we define query to
get possible field values:
$bq = new DBLMYSQLQuery($DBDEF,"brand");
$bq->setFields("id,name as text");
$bq->setOrder("text");
Query is the same as it was for DBLLCField. Now we define the field itself:
$view->addField($brand =& new DBLJSLCField("brand","Brand","",30,"brands.php?",$bq));
$brand->allowEmpty = false;
$brand->referenceURL = "../brand/detail.php?id=";
The fourth parameter to the constructor is width of the readonly textbow,
which shows selected value. Following is a path to script to do the selection.
Here we say it is in the brands.php script. We have to put question
mark at the end, so the field may add parameters (and not care whether there
are some more or not, we could, e.g. use "brand.php?style=1&" for
the script).
Last parameter is the query which defines the values.
We want the field contents to be a hyperlink to brand detail. DBLIB allow
this to be accomplished easy - we just set referenceURL to a script
and the text will be hyperling to this URL. Record id will be appended after
the URL. So the above example will work just fine.
Next we will define two fields to hold first and last year of the model:
$view->addField($f =& new DBLIntegerField("firstYear","First year","",6,4,false));
$f->default = 1990;
$f->minVal = 1940;
$f->maxVal = 2100;
$view->addField($f =& new DBLIntegerField("lastYear","Last year","",6,4,false));
$f->default = 1990;
$f->minVal = 1940;
$f->maxVal = 2100;
There are several things worth noting. The DBLIntegerField (which is descentant
of the DBLNumberField) is created almost same as a DBLTextField. There is
only one extra parameter, called allowNegativeValues. We do not want
negative values entered as the year :-)
Then we set several properties (for both fields) - default, minimum and maximum
values accepted. Of course, minimum/maximum values will be checked on record
entry. Default value will be pre-filled when user creates new record.
There's nothing much interesting below - we just define delete field, links,
formats and query:
// Setup links
$view->detailField = "name";
$view->deleteField = "delete";
// Define formats
$indexFormat = "name;brand;delete";
$detailFormat = "name;brand\nfirstYear;lastYear";
$editFormat = "name;brand\nfirstYear;lastYear";
$filterFormat = "name;brand\nfirstYear;lastYear\n_apply;_order;_clear";
$orderDef = array("name","brand");
$defaultOrder = "name";
// Create query
$q = new DBLMYSQLQuery($DBDEF,"model");
?>
Record index
Now we will look at the record index page (index.php).
Record index script is almost the same as for the previous examples. Except
one thing. As you may have seen, we have not used indexDBConversion.
So we must somehow get brand name to be in the result of the select. The column
must be named as the field with the _txt appended. We will set source
and fields:
$q->setSource("model left join brand on brand.id=model.brand");
$q->setFields("model.*,brand.name as brand_txt");
This is how we will get the name in the list. There is one more thing that
can make problems. If we try to filter by the name field, the SQL where clausule
would be: "WHERE name='xxx'". But SQL engine would complain - there is a name
field in both model and brand table so the where clausule is
ambigous. Now back to the header. When we set:
$name->dbName = "model.name"
all will be OK, since DBLIB will use "model.name" as field name in the where
clausule and all will be clear.
NOTE: We COULD use indexDBConversion. But using this with DBLJSLCField has
another disadvantage. Besides worse performance, it would not be possible
to filter by such field. This is because this field is filtered similarly
as a text field - by entering text pattern. To match the pattern, we must
have the text in the SELECT.
The rest of the script is same as before - here is the complete script:
<?
require('header.php');
require('../../header.html');
$q->setSource("model left join brand on brand.id=model.brand");
$q->setFields("model.*,brand.name as brand_txt");
// Print filter
$view->filter($q,$filterFormat,$orderDef,$defaultOrder);
$view->index($q,$indexFormat);
?>
<P><A HREF="../"><< Menu</A>
</BODY>
</HTML>
Record detail
Record detail is same as before.
Record edit form
We have decided, that we will not allow "first year" to be greater than "last
year" - such input does not make sense. So we have placed two checks in the
edit form script:
<?
require('header.php');
// Javascript check
$view->userJSCheck = " if (document.editFrm.firstYear.value > document.editFrm.lastYear.value) {
alert('Last year should be greater than or equal to first year!');
return false;
}";
// Check year order
$err = array();
if (isset($_POST["firstYear"])) {
if (intval($_POST["firstYear"]) > intval($_POST["lastYear"])) $err[] = "Last year must be greater or equal to first year!";
}
$view->standardEdit($q,$editFormat,"../../header.html",$editFormat,$err);
?>
</BODY>
</HTML>
First, we setup javascript check - we set property of the view. Our javascript
code will be executed after all the checks. When values are not correct, we
will display error message and then return false (canceling submit of the
form).
Then we check if the POST variable is set (means record was posted). When
it was, we check the condition. If this fails, we add error message to the
$err array. The array is passed to the standardEdit method.
We use extended parameters - fourth parameter is format, which lists fields
that are accepted. By default, this is the same as format of the form - you
want these two to differ only in very special cases.
Last parameter is an array. It may contain error message(s). When there are
some, the form is not accepted and error(s) are printed above it.
Brand selecting script
Brand selecting script is in the brands.php file. We will use the
DBLJSExternalSelection class, which provides all we need. First, we have to
include definitions:
<?
require('../../global.php');
require('../../header.html');
require("$DBLIB_PATH/DBLJSExternalSelector.php");
require("$DBLIB_PATH/DBLMYSQLQuery.php");
Next, we define query to list possible values:
$q =& new DBLMYSQLQuery($DBDEF,"brand");
$q->setFields("id, name as text");
$q->setOrder("text");
Create selector and forbid empty value:
$selector = new DBLJSExternalSelector($_GET["formName"],$_GET["name"],"Choose brand",$q);
$selector->allowEmpty = false;
The parameters are:
- Name of the form in the opener window. DBLJSLCField passes it as the
formName GET parameter.
- Name of the field in the form in the opener window. DBLJSLCField passes
it as the name GET parameter.
- Title - shown at the top of the selector
- Query to get the values
Finally we call method to show the selection form. The only parameter is id,
which should by selected by default. DBLJSLCField passes it in the value
GET parameter:
$selector->show($_GET["value"]);
Then we just finish page:
?>
</BODY>
</HTML>
Deleting records
Situation here is similar as in the previous example - we have to add check
to the brand delete script.
Finally
Check how everything works, mainly the checks (with and without javascript
turned on). Also check the hyperlink to brand. Play with the brand selection
- when you write someting to the text widget above, the list will show only
choices starting with the text you wrote.
Also try following: Create a brand for testing. Select this brand in the record,
but do not submit it. Meanwhile, delete the brand. Then try to submit the
record. Guess, what will happen ;-)