<?
/****************************************************************************
* zbase_support.inc : This file gathers modules search, create, modify,
* delete, show, and types_support.
****************************************************************************
* $Id: zbase_support.inc,v 1.18 2000/08/29 01:19:30 massiot Exp $
****************************************************************************
* ZBase - a gateway between the database and the WWW
* Copyright (c) 1999 The ZBase team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************/
if (!isset($GLOBALS[setzbase_support])) {
class zbase_support extends services {
/*
* Object definition variables (constants)
*/
var $TABLE, /* Name of the table. */
$TITLE, /* Default title which will be displayed in tables. */
$FIELDS = array(), /* List of the fields. Note that the attributes
* (see types_support.inc) of every field are
* stored in $ATTR_fieldname class variables. */
$KEYS = array(), /* Set of fields allowing to reference a unique
* row in the table. */
$FOREIGNKEYS = array(), /* Sets of fields that can be used to
* reference one or several rows in that table.
* Eg : array("login", "name", array("building", "room"))
*/
$SHOW_LIST; /* List of fields that will be displayed, by default,
* when you call show_list(). */
/*
* Temporary content of the object
*/
var $row, /* The actual content of the current row.
* Eg : array("login" => "SMITH") */
$old_row, /* The old content of the row, in case of a
* modify(). */
$result_id; /* The result ID returned by the result class
* (see result_support.inc). */
/*
* The SEARCH module
*/
/*
* $dict can be anything useful to identify one or several rows. That
* includes :
* - An array : "field" => "value", ...
* or "field" => array("value", "operator"), ...
* where operator can be =, <, >, <=, >=, !=, <> (default is =)
* Please note that a "like"-style operator is automatically used
* if "value" contains %.
* - An object : in that case we look for the _entire_ set of $KEYS, then
* for each of the sets in $FOREIGNKEYS, in the given object, until
* we find something that can be used for a search.
*
* $order_by can be used as follows :
* - field1
* - array (field1, field2)
* - array (field1 => "desc")
* - array (field1 => "asc","field2"=>"desc")
* But array (field1, field2 => "desc") is incorect and can lead
* to an error or a random order.
*
* As all other modules, in case of errors, the explanation will be put
* in $ZB_ERROR, and the name of the function in $ZB_ERRFUNC.
* If the request is successful, the function returns the number of
* rows matched (search_numrows()).
*/
function search($dict = "", $order_by = "") {
if (is_object($dict)) {
/* Second use of the function */
$gt_dict = $this->search_extractdict($dict);
if (!$gt_dict)
return 0;
} else {
/* The dict is directly usable by the appropriate gate. */
$gt_dict = $dict;
}
return $this->gt_select($dict, $order_by);
} //search
/* Just a placeholder for gt_numrows(). */
function search_numrows() {
return $this->gt_numrows();
} //search_numrows
/* Just a placeholder for gt_fetch_array(). */
function search_fetch_array($nb) {
global $ZB_ERROR;
$temp = $this->gt_fetch_array($nb);
if (!$ZB_ERROR) {
/* Remove extra numeric keys */
foreach ($temp as $key => $val)
if (is_int($key))
unset($temp[$key]);
$this->row = $this->old_row = $temp;
}
} //search_fetch_array
/* Return a dictionary extracted from $object. Used by search(). */
function search_extractdict($object) {
if (srv_isin($object->FIELDS, $this->KEYS))
$gt_keys = $this->KEYS;
else {
foreach(srv_makearray($this->FOREIGNKEYS) as $keys) {
if (srv_isin($object->FIELDS, $keys)) {
$gt_keys = $keys;
break;
}
}
}
if (!$gt_keys)
return;
foreach($gt_keys as $key) {
$gt_dict[$key] = $object->row[$key];
}
return $gt_dict;
} //search_extractdict
/* Continue the search on other tables if needed. */
function search_afterresult() {
/* By default do not do anything. Please feel free to overload this
* function. */
} // search_afterresult
/* Prompt a dialog asking the user to narrow the search. */
function search_narrowresult($nb) {
if (!$this->SEARCH_NARROWFIELD)
return; /* Not supported yet */
$attr = $this->types_getattr($this->SEARCH_NARROWFIELD);
if ($attr["type"] == "text" || in_array("text", $attr["extends"])) {
if ($nb > srv_loadvar("htmlpage", "search_beginnarrow")) {
global $THEME_OBJ;
$THEME_OBJ->th_echo($nb." ".srv_str("html", "search_result_toomany"));
srv_narrowsearch($this->TABLE, $this->SEARCH_NARROWFIELD,
$this->SEARCH_NARROWFIELD);
if (function_exists("srv_stopandask") &&
$nb > srv_loadvar("htmlpage", "search_beginask")) {
srv_stopandask(srv_str("html", "search_result_reallytoomany"));
}
}
}
} //search_narrowresult
/*
* The CREATE module
*/
/* Do everything you need to do to create a new row. Warning : you will
* have a $RESULT_OBJ as a global variable. */
function create() {
global $ZB_ERROR;
$this->create_setup();
$this->create_verify();
if ($ZB_ERROR)
return;
$this->create_maketree();
if ($ZB_ERROR)
return;
$this->create_phase1();
if ($ZB_ERROR) {
$this->create_rollback();
return;
}
$this->create_phase2();
if ($ZB_ERROR) {
$this->create_rollback();
return;
}
$this->create_commit();
if ($ZB_ERROR) {
$this->create_rollback();
return;
}
} //create
/* Retrieve the content of a field from a form. */
function create_retrieve($form, $raw_format = 0) {
/* We assume the calling class has already called $form->form_getnb()
* and form_getobj() and cares about it. */
global $ZB_ERROR, $RESULT_OBJ;
foreach ($this->FIELDS as $field) {
$form->form_getinput($field, $this->row[$field]);
if (!$raw_format) {
$this->row[$field] = $this->types_retrieve($field, $this->row[$field]);
if ($ZB_ERROR) {
/* We need the $RESULT_OBJ to be set up to use this. */
$this->create_setup();
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "retrieve");
return;
}
}
}
} //create_retrieve
/* Prepare $RESULT_OBJ to manage the results of the creation. */
function create_setup() {
global $RESULT_OBJ;
if (!is_object($RESULT_OBJ)) {
/* We create a new result object since we absolutely NEED it, but
* CAUTION : we don't call rlt_end(). */
$RESULT_OBJ = new result;
$RESULT_OBJ->rlt_begin();
$this->result_id = $RESULT_OBJ->rlt_newid();
$RESULT_OBJ->rlt_addroot($this->result_id);
} else
$this->result_id = $RESULT_OBJ->rlt_newid();
$RESULT_OBJ->rlt_addinfo($this->result_id, $this->TABLE,
srv_getfields($this->row, $this->KEYS));
} //create_setup
/* Verify the content of the row. */
function create_verify() {
global $ZB_ERROR, $ZB_ERRFUNC, $RESULT_OBJ;
$this->types_verify();
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "verify");
return;
}
/* Verify that we don't already have a row with the same keys. */
$object = new $this->TABLE;
if ($object->search(srv_getfields($this->row, $this->KEYS))) {
$ZB_ERROR = srv_str("create", "err_exist");
$ZB_ERRFUNC = "zbase:create_verify()";
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "verify");
return;
}
} //create_verify
/* Build the dependances tree. */
function create_maketree() {
global $ZB_ERROR;
if (method_exists($this, "dep_maketree"))
$this->dep_maketree();
if ($ZB_ERROR)
return;
} //create_maketree
/* Phase 1 : We only modify what is safely cancellable. */
function create_phase1() {
global $ZB_ERROR, $RESULT_OBJ;
if ($this->GT_TRANS_SAVVY)
$this->gt_insert($this->row);
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "1");
return;
}
if (method_exists($this, "dep_walk"))
$this->dep_walk("phase1");
if ($ZB_ERROR)
return;
} //create_phase1
/* Phase 2 : We modify what is not safely cancellable. */
function create_phase2() {
global $ZB_ERROR, $RESULT_OBJ;
if (!$this->GT_TRANS_SAVVY)
$this->gt_insert($this->row);
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "2");
return;
}
if (method_exists($this, "dep_walk"))
$this->dep_walk("phase2");
if ($ZB_ERROR)
return;
} //create_phase2
/* End of work, tell the gate to validate the queries, send mail if
* necessary, etc. */
function create_commit() {
global $ZB_ERROR, $RESULT_OBJ;
if (method_exists($this, "dep_reverse_walk"))
$this->dep_reverse_walk("commit");
if ($ZB_ERROR)
return;
$this->gt_commit();
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "1");
return;
}
$RESULT_OBJ->rlt_adddone($this->result_id);
} //create_commit
/* Cancel what we've done. */
function create_rollback() {
global $ZB_ERROR, $RESULT_OBJ;
if (method_exists($this, "dep_reverse_walk"))
$this->dep_reverse_walk("rollback");
$this->gt_rollback();
} //create_rollback
/* Called by create_result.php after a new row has been created. */
function create_afterresult() {
/* By default display the created row */
$this->show_row();
} //create_afterresult
/*
* The MODIFY module
* For comments, please look at the create module, and adapt adequately.
*/
/* Do everything you need to do to modify a row. Warning : you will end up
* with a $RESULT_OBJ as a global variable. */
function modify() {
global $ZB_ERROR;
$this->modify_setup();
$this->modify_verify();
if ($ZB_ERROR)
return;
$this->modify_maketree();
if ($ZB_ERROR)
return;
$this->modify_phase1();
if ($ZB_ERROR) {
$this->modify_rollback();
return;
}
$this->modify_phase2();
if ($ZB_ERROR) {
$this->modify_rollback();
return;
}
$this->modify_commit();
if ($ZB_ERROR) {
$this->modify_rollback();
return;
}
} //modify
/* Retrieve the content of a field from a form. */
function modify_retrieve($form, $raw_format) {
/* We assume the calling class has already called $form->form_getnb()
* and form_getobj() and cares about it. */
foreach ($this->FIELDS as $field) {
$form->form_getinput($field, &$temp);
/* FIXME !! */
// if (strlen($temp)) {
$this->row[$field] = $temp;
if (!$raw_format) {
$this->row[$field] = $this->types_retrieve($field, $this->row[$field]);
if ($ZB_ERROR) {
/* We need the $RESULT_OBJ to be set up to use this. */
$this->modify_setup();
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "retrieve");
return;
}
}
// }
}
} //modify_retrieve
function modify_setup() {
global $RESULT_OBJ;
if (!is_object($RESULT_OBJ)) {
/* We create a new result object since we absolutely NEED it, but
* CAUTION : we don't call rlt_end(). */
$RESULT_OBJ = new result;
$RESULT_OBJ->rlt_begin();
$this->result_id = $RESULT_OBJ->rlt_newid();
$RESULT_OBJ->rlt_addroot($this->result_id);
} else
$this->result_id = $RESULT_OBJ->rlt_newid();
$RESULT_OBJ->rlt_addinfo($this->result_id, $this->TABLE,
srv_getfields($this->row, $this->KEYS));
} //modify_setup
function modify_verify() {
global $ZB_ERROR, $ZB_ERRFUNC, $RESULT_OBJ;
$this->types_verify();
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "verify");
return;
}
} //modify_verify
function modify_maketree() {
global $ZB_ERROR;
if (method_exists($this, "dep_maketree"))
$this->dep_maketree();
if ($ZB_ERROR)
return;
} //modify_maketree
function modify_phase1() {
global $ZB_ERROR, $RESULT_OBJ;
if ($this->GT_TRANS_SAVVY)
$this->gt_update($this->row, $this->old_row);
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "1");
return;
}
if (method_exists($this, "dep_walk"))
$this->dep_walk("phase1");
if ($ZB_ERROR)
return;
} //modify_phase1
function modify_phase2() {
global $ZB_ERROR, $RESULT_OBJ;
if (!$this->GT_TRANS_SAVVY)
$this->gt_update($this->row, $this->old_row);
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "2");
return;
}
if (method_exists($this, "dep_walk"))
$this->dep_walk("phase2");
if ($ZB_ERROR)
return;
} //modify_phase2
function modify_commit() {
global $ZB_ERROR, $RESULT_OBJ;
if (method_exists($this, "dep_walk"))
$this->dep_walk("commit");
if ($ZB_ERROR)
return;
$this->gt_commit();
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "1");
return;
}
$RESULT_OBJ->rlt_adddone($this->result_id);
} //modify_commit
function modify_rollback() {
global $ZB_ERROR, $RESULT_OBJ;
if (method_exists($this, "dep_reverse_walk"))
$this->dep_reverse_walk("rollback");
$this->gt_rollback();
} //modify_rollback
/* Called by modify_result.php after a row has been modified. */
function modify_afterresult() {
/* By default display the modified row */
$this->show_row();
} //modify_afterresult
/*
* The DELETE module
* For comments, please see the create module and adapt adequately.
*/
function delete() {
global $ZB_ERROR;
$this->delete_setup();
$this->delete_verify();
if ($ZB_ERROR)
return;
$this->delete_maketree();
if ($ZB_ERROR)
return;
$this->delete_phase1();
if ($ZB_ERROR) {
$this->delete_rollback();
return;
}
$this->delete_phase2();
if ($ZB_ERROR) {
$this->delete_rollback();
return;
}
$this->delete_commit();
if ($ZB_ERROR) {
$this->delete_rollback();
return;
}
} //delete
function delete_setup() {
global $RESULT_OBJ;
if (!is_object($RESULT_OBJ)) {
/* We create a new result object since we absolutely NEED it, but
* CAUTION : we don't call rlt_end(). */
$RESULT_OBJ = new result;
$RESULT_OBJ->rlt_begin();
$this->result_id = $RESULT_OBJ->rlt_newid();
$RESULT_OBJ->rlt_addroot($this->result_id);
} else
$this->result_id = $RESULT_OBJ->rlt_newid();
$RESULT_OBJ->rlt_addinfo($this->result_id, $this->TABLE,
srv_getfields($this->row, $this->KEYS));
} //delete_setup
function delete_verify() {
/* We have nothing to verify, but maybe the user will overload this
* function. */
} //delete_verify
function delete_maketree() {
global $ZB_ERROR;
if (method_exists($this, "dep_maketree"))
$this->dep_maketree();
if ($ZB_ERROR)
return;
} //delete_maketree
function delete_phase1() {
global $ZB_ERROR, $RESULT_OBJ;
if ($this->GT_TRANS_SAVVY)
$this->gt_delete(srv_getfields($this->row, $this->KEYS));
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "1");
return;
}
if (method_exists($this, "dep_walk"))
$this->dep_walk("phase1");
if ($ZB_ERROR)
return;
} //delete_phase1
function delete_phase2() {
global $ZB_ERROR, $RESULT_OBJ;
if (!$this->GT_TRANS_SAVVY)
$this->gt_delete(srv_getfields($this->row, $this->KEYS));
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "2");
return;
}
if (method_exists($this, "dep_walk"))
$this->dep_walk("phase2");
if ($ZB_ERROR)
return;
} //delete_phase2
function delete_commit() {
global $ZB_ERROR, $RESULT_OBJ;
if (method_exists($this, "dep_reverse_walk"))
$this->dep_reverse_walk("commit");
if ($ZB_ERROR)
return;
$this->gt_commit();
if ($ZB_ERROR) {
$RESULT_OBJ->rlt_adderror($this->result_id, srv_geterr(), "1");
return;
}
$RESULT_OBJ->rlt_adddone($this->result_id);
} //delete_commit
function delete_rollback() {
global $ZB_ERROR, $RESULT_OBJ;
if (method_exists($this, "dep_reverse_walk"))
$this->dep_reverse_walk("rollback");
$this->gt_rollback();
} //delete_rollback
/* Called by delete_result.php after a row has been deleted. */
function delete_afterresult() {
/* By default do not do anything */
} //delete_afterresult
/****************************************************************************
* types_support : Support for type conversion routines
****************************************************************************/
/* Cache the attributes of the fields. */
var $attributes_cache;
/*
* Reminder : text, int, float are standard primary types (ie. MUST be
* understood by all modules).
*
* Other types defined here are secondary types.
* Modules that don't understand them SHOULD fall back to the closest
* type, using the 'extends' attribute. You can define your own secondary
* types in zbase.inc.
*/
/*
* Reminder : the valid attributes for both types and fields (a field
* automatically inherits its type's attributes) are :
* type Type of the field
* extends When defining the type : the first parent of the type
* When returned by srv_getattr : all the parents of the type
* display_as The type that can be used to display this type, in
* case the theme doesn't know anything about it. If
* defined, will be used preferably to 'extends' in themes.
* store_as The type that can be used to store this type, in
* case the gate doesn't know anything about it. If
* defined, will be used preferably to 'extends' in gates.
* min Minimum value (for types derived from int, float, date
* and time only)
* max Maximum value (idem)
* size Maximum size (in bytes) of the field
* showsize Average size (in bytes) of the field
* vsize Vertical size (in lines) of the field
* caption Caption to use in the SHOW module
* regexp Regular Expression the field must match
* default Default content of the field
* required TRUE if the field must not be empty
* menu The different options (only for the menu type)
* help String to display as a help balloon
* bgcolor The background color of the cell
* func_retrieve Function used to retrieve the content of the field
* func_verify Function used to verify the content of the field
* func_show Function used to display the content of the field
* func_form Function used to edit the content of the field
* func_link Function used to return a link associated with the field
* sequence Name of the sequence in the database [sequence type only]
* ref_table Table this field references to [reference type only]
* ref_field Field to display in that table [reference type only]
* Other attributes may be added in the future. You should ignore them
* without displaying an error message.
*/
/*
* Standard primary types
*/
var $TYPES_PRIMARY = array ("int", "float", "text"),
$TYPEATTR_text = array("func_show" => "types_show_text"),
$TYPEATTR_int = array("regexp" => "^[0-9]*\$", "showsize" => 8),
$TYPEATTR_float = array("regexp" => "^\\-?[0-9]*(\\.[0-9]*)?\$",
"showsize" => 15);
function types_show_text($field) {
return stripslashes($this->row[$field]);
} //types_show_text
/*
* Standard secondary types
*/
/* MENU */
var $TYPEATTR_menu = array("extends" => "int",
"min" => 1,
"display_as" => "text",
"func_show" => "types_show_menu",
"func_verify" => "types_verify_menu");
/* The menu type requires moreover a 'menu' attributes, that is an
* array of all items in the menu. */
/* Used to convert $this->row[$field] to a value that can be displayed
* by the theme. */
function types_show_menu($field)
{
$ATTR = $this->types_getattr($field);
$menu = $ATTR["menu"];
$value = $this->row["$field"];
return $menu[$value - 1];
} //types_show_menu
/* Used to verify that the content of the field (after retrieve) is correct. */
function types_verify_menu($field)
{
if (strlen($this->row[$field]) == 0)
return FALSE;
$ATTR = $this->types_getattr($field);
$menu = $ATTR["menu"];
$value = $this->row["$field"];
return ($menu[$value - 1] == "");
} //types_verify_menu
/* BOOLEAN */
var $TYPEATTR_boolean = array("extends" => "menu",
"min" => 1, "max" => 2,
"menu" => array ("True", "False"),
"func_show" => "types_show_boolean",
"func_retrieve" => "types_retrieve_boolean");
function types_show_boolean($field)
{
global $ZB_TRUE;
$value = $this->row["$field"];
if ($value==$ZB_TRUE) return srv_str("show","boolean_true");
else return srv_str("show","boolean_false");
} //types_show_boolean
function types_retrieve_boolean($field, $value)
{
/* The $value is 1 for TRUE and 0 for FALSE. Let's convert it into
* ZB's standards. */
global $ZB_TRUE, $ZB_FALSE;
if ($value == 1)
return $ZB_TRUE;
else
return $ZB_FALSE;
} //types_retrieve_boolean
/* EMAIL */
var $TYPEATTR_email = array("extends" => "text", "showsize" => 20,
"regexp" =>
"^([a-zA-Z0-9_]|\\-|\\.)+@(([a-zA-Z0-9_]|\\-)+\\.)+[a-zA-Z]{2,4}\$",
"func_link" => "types_email_link");
function types_email_link($field) {
return "mailto:".$this->row[$field];
}
/* PASSWORD */
var $TYPEATTR_password = array("extends" => "text", "showsize" => 10,
"func_show" => "types_show_password",
"func_form" => "types_form_password",
"func_retrieve" => "types_retrieve_password");
function types_show_password($field) {
/* Of course we don't show a password ! */
return "********";
} //types_show_password
function types_form_password($field, &$more_attr) {
return "********";
} //types_form_password
function types_retrieve_password($field, $value) {
if ($value == "********")
/* The password hasn't been modified. */
return $this->old_row[$field];
else
/* Encrypt the new password. */
return crypt($value);
} //types_retrieve_password
/* DATE */
var $TYPEATTR_date = array("extends" => "int",
"min" => 0, /* An invalid date is -1. */
"display_as" => "text",
"func_show" => "types_date_unix2ISO",
"func_form" => "types_date_unix2ISO",
"func_retrieve" => "types_date_ISO2unix",
"showsize" => 15);
/* func_show, func_form */
function types_date_unix2ISO($field)
{
if ($this->row[$field])
return date ("Y-m-d",$this->row["$field"]);
} //types_date_unix2ISO
/* func_retrieve */
function types_date_ISO2unix($field, $date)
{
if ($date) {
if (ereg("^[0-9]{1,2}-[0-9]{1,2}$",$date))
$date = date ("Y-").$date;
ereg("([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})",$date,$temp);
return mktime(0,0,0,$temp[2],$temp[3],$temp[1]);
/* Return -1 in case of error. */
}
} //types_date_ISO2unix
/* TIME */
var $TYPEATTR_time = array("extends" => "int",
"min" => 0, /* An invalid time is -1. */
"display_as" => "text",
"func_show" => "types_time_unix2ISO",
"func_form" => "types_time_unix2ISO",
"func_retrieve" => "types_time_ISO2unix",
"showsize" => 15);
/* func_show, func_form */
function types_time_unix2ISO($field)
{
if ($this->row[$field])
return date ("H:i:s",$this->row["$field"]);
} //types_time_unix2ISO
/* func_retrieve */
function types_time_ISO2unix($field, $time)
{
if ($time) {
if (ereg("^[0-9]{1,2}:[0-9]{1,2}$",$time))
$time = $time.":00";
ereg("([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})",$time,$temp);
return mktime ($temp[1],$temp[2],$temp[3], 1, 2, 1970);
}
} //types_time_ISO2unix
/* SEQUENCE */
var $TYPEATTR_sequence = array("extends" => "int",
"min" => 0, /* -1 is an invalid sequence ID. */
"func_retrieve" => "types_sequence_retrieve");
/* The sequence type requires moreover a 'sequence' attribute, that is
* the name of the sequence that will be passes to gt_nextseq() to get
* the next sequence ID. */
/* If no ID is given, get a new one from gt_nextseq(). If no gt_nextseq()
* function is provided, ZBase will erase your hard drives and send a
* hurricane to Florida. */
function types_sequence_retrieve($field, $value) {
if (strlen($value) == 0) {
global $ZB_ERROR;
$attr = $this->types_getattr($field);
$value = $this->gt_nextseq($attr["sequence"]);
if ($ZB_ERROR)
return -1;
/* FIXME !!!!!!!!!!!! */
$toto = "FORM_".$field;
global $$toto;
$$toto = $value;
}
return $value;
} //types_sequence_retrieve
/* REFERENCE */
var $TYPEATTR_reference = array("extends" => "int", "display_as" => "text",
"func_show" => "types_show_reference",
"func_form" => "types_form_reference",
"func_retrieve" => "types_retrieve_reference",
"func_link" => "types_link_reference",
"display_as" => "menu");
function types_show_reference($field) {
if (strlen($this->row[$field])) {
$attr = $this->types_getattr($field);
srv_include($attr["ref_table"]);
$obj = new $attr["ref_table"];
$obj->search(array($field => $this->row[$field]));
if ($obj->search_numrows() == 1) {
$obj->search_fetch_array(0);
return $obj->types_show($attr["ref_field"]);
}
else
return $this->row[$field];
}
} //types_show_reference
function types_form_reference($field, &$more_attr) {
$attr = $this->types_getattr($field);
if (!$attr["required"])
$menu["-1"] = "";
srv_include($attr["ref_table"]);
$obj = new $attr["ref_table"];
$obj->search(array(), $attr["ref_field"]);
$nb = $obj->search_numrows();
for ($i = 0; $i < $nb; $i++) {
$obj->search_fetch_array($i);
/* -1 because form_std.inc automatically adds 1 to each menu index */
$menu[$obj->row[$field]-1] = $obj->types_show($attr["ref_field"]);
}
$more_attr["menu"] = $menu;
return $this->row[$field];
} //types_form_reference
function types_retrieve_reference($field, $value) {
/* empty value */
if (!$value) $value = "";
return $value;
} //types_retrieve_reference
function types_link_reference($field) {
$attr = $this->types_getattr($field);
return srv_loadvar("htmlpage", "search_result")
."?FORM_NB=1&FORM_1_table=".$attr["ref_table"]
."&FORM_1_ATTR=a%3A1%3A%7Bs%3A3%3A%22raw%22%3Bi%3A1%3B%7D"
."&FORM_1_field=$field&FORM_1_operator=%3D&FORM_1_value="
.$this->row[$field];
} //types_link_reference
/* URL */
var $TYPEATTR_url = array("extends" => "text", "showsize" => 30,
"default" => "http://www.", "colspan" => 3,
"func_link" => "types_url_link");
function types_url_link($field) {
return $this->row[$field];
} //types_url_link
/* PHONE */
var $TYPEATTR_phone = array("extends" => "text", "showsize" => 20,
"default" => "(33) ",
"func_retrieve" => "types_retrieve_phone");
function types_retrieve_phone($field, $value) {
if (ereg("^\(33\)[[:space:]]*([0-9]{2})[[:space:]]*([0-9]{2})[[:space:]]*([0-9]{2})[[:space:]]*([0-9]{2})[[:space:]]*([0-9]{2})$",
$value, $result))
return "(33) ".$result[1]." ".$result[2]." ".$result[3]." ".$result[4]
." ".$result[5];
else
return $value;
} //types_retrieve_phone
/* UPPERTEXT */
var $TYPEATTR_uppertext = array("extends" => "text",
"func_retrieve" => "types_retrieve_uppertext");
function types_retrieve_uppertext($field, $value) {
return strtoupper($value);
} //types_retrieve_uppertext
/* LOWERTEXT */
var $TYPEATTR_lowertext = array("extends" => "text",
"func_retrieve" => "types_retrieve_lowertext");
function types_retrieve_lowertext($field, $value) {
return strtolower($value);
} //types_retrieve_lowertext
/*
* Types inheritance management
*/
/* Return the attributes of $field (cached in $attributes_cache by the
* class constructor, using types_computeattr). */
function types_getattr($field) {
return $this->attributes_cache[$field];
} //types_getattr
/* Return the attributes of a field, after all relationships of inheritance
* are computed. */
function types_computeattr($field)
{
$varname = "ATTR_$field";
$attr_field = srv_makearray($this->$varname);
$type = $attr_field["type"] ? $attr_field["type"] : "text";
$extends = $this->types_getextendsparents($type);
$display_as = $this->types_getdisplayasparents ($type);
$store_as = $this->types_getstoreasparents($type);
$result = $attr_field;
/* Build the attributes list of the type. */
foreach ($extends as $type)
{
$varname = "TYPEATTR_$type";
$attr = srv_makearray($this->$varname);
foreach($attr as $key => $value)
if (!isset($result[$key])) $result["$key"] = $value;
}
/* Overload extends and display/store_as */
$result["extends"] = $extends;
$result["display_as"] = $display_as;
$result["store_as"] = $store_as;
return $result;
} //types_computeattr
/* The following methods are private : */
/* Return an array containing all the parents of a type */
function types_getextendsparents($type)
{
if (srv_isin ($this->TYPES_PRIMARY, $type)) return array ($type);
else
{
$varname = "TYPEATTR_$type";
$TYPEATTR = $this->$varname;
return array_merge(array($type),$this->types_getextendsparents($TYPEATTR["extends"]));
}
} //types_getextendsparents
/* Return an array containing all the "display_as" parents of a type */
function types_getdisplayasparents($type)
{
if (srv_isin ($this->TYPES_PRIMARY, $type)) return array ($type);
else
{
$varname = "TYPEATTR_$type";
$TYPEATTR = $this->$varname;
$parent = $TYPEATTR["display_as"];
if ($parent=="") $parent = $TYPEATTR["extends"];
return array_merge(array($type),$this->types_getstoreasparents($parent));
}
} //types_getdisplayasparents
/* Return an array containing all the "store_as" parents of a type */
function types_getstoreasparents($type)
{
if (srv_isin ($this->TYPES_PRIMARY, $type)) return array ($type);
else
{
$varname = "TYPEATTR_$type";
$TYPEATTR = $this->$varname;
$parent = $TYPEATTR["store_as"];
if ($parent=="") $parent = $TYPEATTR["extends"];
return array_merge(array($type),$this->types_getstoreasparents($parent));
}
} //types_getstoreasparents
/* We currently use the constructor of the class to pre-compute the
* attributes of each field. They're stored in $attributes_cache. */
function zbase_support() {
foreach ($this->FIELDS as $field) {
$this->attributes_cache[$field] = $this->types_computeattr($field);
}
services::services();
} //zbase_support
/*
* Utilities used to choose a type in all parents of the field.
*/
/* Choose the best display type for the specified field in the specified
* known types list (which countains at least the 3 primary types) */
function types_bestdisplay ($field, $knowntypes)
{
$attr = $this->types_getattr($field);
$display_as = $attr ["display_as"];
foreach ($display_as as $type)
if (srv_isin ($knowntypes, $type)) return $type;
} //types_bestdisplay
/* types_beststore : The same, for the storage. */
function types_beststore ($field, $knowntypes="")
{
if ($knowntypes=="") $knowntypes = $this->GT_KNOWN_TYPES;
$attr = $this->types_getattr($field);
$store_as = $attr ["store_as"];
foreach ($store_as as $type)
if (srv_isin ($knowntypes, $type)) return $type;
} //types_beststore
/*
* Content validation
*/
/* Verify that the variables in $row are consistent with their attributes.
* Return FALSE or an array of couples (name, reason), where reason can
* be :
* regexp The regular expression check has failed
* size Field too large
* min Value too small
* max Value too high
* func Check failed in the func_verify function
* Other reasons may be added in the future. You should display a standard
* error message for them.
*/
function types_verify()
{
foreach ($this->FIELDS as $field)
{
$field_test = $this->types_verify_field ($field);
if ($field_test)
{
$error[] = $field." (".$field_test.")";
}
}
if ($error)
srv_seterr("types_support:types_verify()",
srv_str("types", "verify_err").implode(", ", $error));
} //types_verify
/* The following functions are private : */
/* Verify the coherence between the content of a field and its attributes. */
function types_verify_field($field)
{
$ATTR = $this->types_getattr ($field);
$value = $this->row["$field"];
// Checks structural information first
// -> size
if ($ATTR["size"] > 0 && strlen($value)>$ATTR["size"])
return "size";
// -> regexp
if ($ATTR["regexp"] != "" && strlen($value))
{
if (!ereg($ATTR["regexp"],$value)) return "regexp";
}
if ($ATTR["required"] && strlen($value) == 0)
return "required";
// Interval control
if ($ATTR["min"] != "" && $ATTR["min"] > $value) return "min";
if ($ATTR["max"] != "" && $ATTR["max"] < $value) return "max";
// Custom control
if ($ATTR["func_verify"] != "")
{
$func=$ATTR["func_verify"];
if ($this->$func($field)) return "func_verify";
}
} //types_verify_field
/*
* Content manipulation
*/
/* Return the content of the field ready for displaying (e.g. transform
* the boolean type in yes or no). */
function types_show($field)
{
// The data is supposed to have already been checked by types_verify
$attr_field = $this->types_getattr($field);
if ($attr_field["func_show"] != "")
return $this->$attr_field["func_show"]($field);
else
return $this->row[$field];
} //types_show
/* Return the content of the field ready for editing (ie. call the
* func_form functions). */
function types_form($field, &$more_attr)
{
// The data is supposed to have already been checked by types_verify
$attr_field = $this->types_getattr($field);
if ($attr_field["func_form"] != "")
return $this->$attr_field["func_form"]($field, &$more_attr);
else
return $this->row[$field];
} //types_form
/* Put $value in $row after calling func_retrieve. */
function types_retrieve($field, $value)
{
$attr_field = $this->types_getattr($field);
if ($temp = $attr_field["func_retrieve"])
return $this->$temp($field, stripslashes($value));
else
return $value;
} //types_retrieve
/* Set field value to defaults. */
function types_default($fields = "") {
if (!$fields)
$fields = $this->FIELDS;
else
$fields = srv_makearray($fields);
foreach($fields as $field) {
$attr_field = $this->types_getattr($field);
$this->row["$field"] = $attr_field["default"];
}
} //types_default
/****************************************************************************
* show_support.inc : Support for display routines
****************************************************************************/
/* Show a simple row, allowing optionnally to edit it. Uses the row helper
* intensively. */
function show_row($fields = "", $to_edit = "", $to_merge = "", $link = "") {
global $ROW_OBJ;
if (!is_object($ROW_OBJ)) {
$ROW_OBJ = new row;
if ($this->TITLE)
$attributes = array("title" => strtoupper($this->TITLE));
else
$attributes = array("title" => strtoupper($this->TABLE));
$attributes["banner"] = $this->show_getbanner();
if ($link)
$attributes["link"] = $link;
$ROW_OBJ->row_begin($attributes);
$end_row = TRUE;
}
$ROW_OBJ->row_newobj(array("name" => $this->TABLE, "keys" => srv_getfields($this->row, $this->KEYS)));
if (!$fields || $fields == "*")
$fields = $this->FIELDS;
if ($to_edit == "*")
$to_edit = $this->FIELDS;
if ($to_merge == "*")
$to_merge = $fields;
$to_edit = srv_makearray($to_edit);
$to_merge = srv_makearray($to_merge);
foreach ($this->FIELDS as $field) {
$attr = $this->types_getattr($field);
$caption_attr = array("style" => 0);
$attr["style"] = $this->show_getstyle($field);
$attr["bgcolor"] = $this->show_getbgcolor($field);
if (!srv_isin($fields, $field))
$attr["type"] = $attr["display_as"] = array("hidden");
if (srv_isin($to_merge, $field))
$attr["merged"] = TRUE;
if ($link = $this->show_getfieldlink($field))
$attr["link"] = $link;
if (srv_isin($this->KEYS, $field)) {
/* Make keys larger */
$caption_attr["colspan"] = 2;
if ($attr["colspan"] < 2)
$attr["colspan"] = 2;
}
/* Retrieve the content of the field */
$more_attr = "";
if (!srv_isin($to_edit, $field))
$content = $this->types_show($field);
else {
$content = $this->types_form($field, &$more_attr);
if ($more_attr)
$attr = array_merge($attr, $more_attr);
/* Clear link flag */
$attr["link"] = "";
}
if ($attr["type"][0] != "hidden")
/* Make two cells */
$ROW_OBJ->row_newfield($attr["caption"] ? $attr["caption"] : $field,
$content, $caption_attr, $attr,
(srv_isin($to_edit, $field)) ? $field : "");
else
echo $ROW_OBJ->form->form_newinput($field, $content, $attr);
}
if ($end_row) {
$ROW_OBJ->row_end();
$ROW_OBJ = ""; /* clean up */
}
} //show_row
/* Manage a list of several rows. Uses the list helper. */
function show_list_begin($fields = "", $link = "") {
if (!$fields)
$fields = $this->SHOW_LIST;
if (!$fields)
$fields = $this->FIELDS;
global $LIST_OBJ;
if (!is_object($LIST_OBJ)) {
$LIST_OBJ = new zblist;
if ($this->TITLE)
$attributes = array("title" => strtoupper($this->TITLE));
else
$attributes = array("title" => strtoupper($this->TABLE));
if ($link)
$attributes["link"] = $link;
foreach ($fields as $field) {
$field_attr = $this->types_getattr($field);
$headers[$field] = $field_attr["caption"] ?
$field_attr["caption"] : $field;
$headers_attr[$field] = array("style" => 0,
"colspan" => $field_attr["colspan"]);
}
$LIST_OBJ->list_begin($attributes, $headers, $headers_attr);
}
} //show_list_begin
function show_list($fields = "", $to_edit = "", $to_merge = "") {
if (!$fields)
$fields = $this->SHOW_LIST;
if (!$fields)
$fields = $this->FIELDS;
global $LIST_OBJ;
foreach ($fields as $field) {
/* Retrieve the content of the field */
$attributes[$field] = $this->types_getattr($field);
$attributes[$field]["style"] = $this->show_getstyle($field);
$attributes[$field]["bgcolor"] = $this->show_getbgcolor($field);
if (srv_isin($to_merge, $field))
$attributes[$field]["merged"] = TRUE;
if ($link = $this->show_getfieldlink($field))
$attributes[$field]["link"] = $link;
$more_attr = "";
if (!srv_isin($to_edit, $field))
$contents[$field] = $this->types_show($field);
else {
$contents[$field] = $this->types_form($field, &$more_attr);
if ($more_attr)
$attributes[$field] = array_merge($attributes[$field], $more_attr);
$attributes[$field]["link"] = "";
}
}
$i = 1;
$LIST_OBJ->list_newrow($contents, $attributes,
srv_loadvar("htmlpage", "search_result")."?"
.$this->show_getdict(&$i)."&FORM_NB=".($i-1),
array("name" => $this->TABLE,
"keys" => srv_getfields($this->row,
$this->KEYS)),
$to_edit);
} //show_list
function show_list_end() {
global $LIST_OBJ;
$LIST_OBJ->list_end();
$LIST_OBJ = "";
} //show_list_end
/* Return a URL-style pointer to this object, including its entire content
* (for use in create.php).
* $form_nb is the current form number used by the form class (usually 1)
*/
function show_getfields($form_nb, $fields = "", $to_merge = "") {
if (!$fields)
$fields = $this->FIELDS;
$attributes["name"] = $this->TABLE;
$attributes["keys"] = srv_getfields($this->row, $this->KEYS);
$attributes["raw"] = 1;
$temp[] = "FORM_".$form_nb."_ATTR=".urlencode(serialize($attributes));
foreach ($fields as $field) {
if (srv_isin($to_merge, $field))
$temp[] = "FORM_".$field."=".urlencode($this->row[$field]);
else
$temp[] = "FORM_".$form_nb."_".$field."=".urlencode($this->row[$field]);
}
return implode("&", $temp);
} //show_getfields
/* Return a URL-style pointer to this object, including only its keys (for
* use in modify.php and delete_result.php). */
function show_getkeys($form_nb) {
$attributes["name"] = $this->TABLE;
$attributes["keys"] = srv_getfields($this->row, $this->KEYS);
$attributes["omitted"] = 1;
$temp[] = "FORM_".$form_nb."_ATTR=".urlencode(serialize($attributes));
return implode("&", $temp);
} //show_getkeys
/* Return a URL-style pointer to this object, including something suitable
* for search_result.php. */
function show_getdict($form_nb, $dict = "") {
if (!$dict)
$dict = srv_getfields($this->row, $this->KEYS);
foreach($dict as $key => $val) {
$temp[] = "FORM_".$form_nb."_table=".$this->TABLE;
$temp[] = "FORM_".$form_nb."_ATTR=".urlencode(serialize(array("raw" => 1)));
$temp[] = "FORM_".$form_nb."_field=".$key;
$temp[] = "FORM_".$form_nb."_operator=".urlencode("=");
$temp[] = "FORM_".$form_nb."_value=".urlencode($val);
$form_nb++;
}
return implode("&", $temp);
} //show_getdict
/*
* Following functions are local to the show_* files ONLY.
*/
/* Return a standard banner. */
function show_getbanner() {
/* A simple banner with four buttons, search, insert, modify, delete */
return array(srv_str("show", "banner_main") => array(
srv_str("show", "banner_search")
=> srv_url(srv_loadvar("htmlpage", "search_result")."?FORM_NB=1&"
.$this->show_getdict(1)),
srv_str("show", "banner_create")
=> srv_url(srv_loadvar("htmlpage", "create")."?FORM_NB=1&"
.$this->show_getfields(1, srv_delfields($this->FIELDS, $this->KEYS))),
srv_str("show", "banner_modify")
=> srv_url(srv_loadvar("htmlpage", "modify")."?FORM_NB=1&"
.$this->show_getkeys(1)),
srv_str("show", "banner_delete")
=> srv_url(srv_loadvar("htmlpage", "delete")."?FORM_NB=1&"
.$this->show_getkeys(1))
));
} //show_getbanner
/* Return a link that can be used as a "link" attribute for the table
* helper. */
function show_getfieldlink($field) {
$attr = $this->types_getattr($field);
if ($attr["link"])
return $attr["link"];
elseif ($temp = $attr["func_link"])
return $this->$temp($field);
if (is_array($this->DEP_FIELDS)) {
$link = srv_loadvar("htmlpage", "search_result");
foreach ($this->DEP_FIELDS as $table => $fields) {
if (srv_isin(srv_makearray($fields), $field)) {
/* We have found a possible table. */
srv_include($table);
$object = new $table;
if ($dict = $object->search_extractdict($this))
return $link."?FORM_NB=1&".$object->show_getdict(1, $dict);
}
}
}
} //show_getfieldlink
/* Return a bitmask value for the style attribute of tables. */
function show_getstyle($field) {
$attr = $this->types_getattr($field);
return $attr["style"] | 1; /* bold */
} //show_getstyle
/* Can return a color value for the bgcolor attribute of tables. */
function show_getbgcolor($field) {
$attr = $this->types_getattr($field);
return $attr["bgcolor"];
} //show_getbgcolor
/*****************************************************************************
* gate_support : Common methods for all gates
*****************************************************************************/
/*
* Public methods. Bear in mind that these functions are provided here as
* some useful tools for the developers of new gates, but you're not
* obliged to use them.
*/
/* Return an array of the names of the fields that have changed between
* $row and $old_row. Should not be used by a class higher than
* gate_support. */
function gt_diffrows($old_row, $row) {
$answer = array();
foreach($this->FIELDS as $field)
{
if ($old_row[$field]!=$row[$field])
$answer[]=$field;
}
return $answer;
} //gt_diffrows
/* Encode the value of the field so that it can be understood by the
* database with the given operator. This function has been tested with
* PostgreSQL, it is more than expected that you will have to overload
* it for other databases. Should not be used by a class higher than
* gate_support. */
function gt_mask($field, $value) {
$type=$this->types_beststore($field);
$value = srv_makearray($value);
list($value, $operator) = $value;
if (strlen($operator) == 0) $operator="=";
if (substr($operator,0,1) == "!") {
$negation="not ";
$operator=substr($operator,1);
} else
$negation="";
/* Hybrid operator where empty == not taken into account. */
if ($operator == "=?") {
if (strlen($value))
$operator = "=";
else
return "true";
}
/* Operators used for numbers. */
if ( srv_isin(array("=", ">", "<", ">=", "<="),$operator)
&& srv_isin(array("float", "int"), $type))
if (strlen($value))
return "$negation"."$field $operator $value";
else
return "$negation"."$field is NULL";
/* Operators used for strings (and unknown types). */
/* Hybrid operator to search a string which "begins with". */
if ($operator == "=%" && $type == "text") {
$value = "^$value";
$operator = "#";
}
/* Curious operator allowing to search regular expressions. */
if ($operator == "#" && $type == "text") {
$value=strtolower($value);
$value=ereg_replace("[éèëêe]","\[éëêèe\]",$value);
$value=ereg_replace("[aàâä]","\[aàâä\]",$value);
$value=ereg_replace("[iïî]","\[iïî\]",$value);
$value=ereg_replace("[uüûù]","\[uüûù\]",$value);
$value=ereg_replace("[oöô]","\[oöô\]",$value);
$value=ereg_replace("[yÿ]","\[yÿ\]",$value);
$value=ereg_replace("[cç]","\[cç\]",$value);
return "$negation"."$field ~* '$value'";
}
/* Default return */
return "$negation"."$field ".$operator." '".$value."'";
} //gt_mask
/* Encode the entire dictionary with the previous function. */
function gt_where($dict) {
if ($dict) {
$and="";
$request =" where ";
foreach ($dict as $field => $value)
{
$mask=$this->gt_mask($field,$value);
if ($mask==-1) return -1;
$request.= $and.$mask;
$and = " AND ";
}
return $request;
}
} //gt_where
/* Translate ZBase vars (in $row) into something understandable by a
* database server. */
function gt_encode_value($value,$field) {
switch ($this->types_beststore($field)) {
case "int":
case "float":
if (strlen($value))
return $value;
else
return "NULL";
break;
case "text":
default:
return "'".addslashes(trim($value))."'";
}
} //gt_encode_value
/* Encode the entire row with the previous function. */
function gt_encode_row($fields) {
foreach ($this->FIELDS as $field)
$answer["$field"] = $this->gt_encode_value($fields[$field], $field);
return $answer;
} //gt_encode_row
} //class zbase_support
$GLOBALS[setzbase_support] = TRUE;
} //setzbase_support
?>