Source for file dbchoicelist.php
Documentation is available at dbchoicelist.php
* A choice list based on an SQL statement
* @author Stuart Prescott
* @copyright Copyright Stuart Prescott
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @subpackage FormsLibrary
/** Load ancillary functions */
require_once 'inc/typeinfo.php';
require_once 'dbobject.php';
* A choice list based on an SQL statement.
* Primitive class on which selection lists can be built from the
* results of an SQL query. This may be used to determine the choices
* that a user is permitted to select (e.g. dropdown list or radio buttons)
* or also to permit additional entries to be created.
* Used in a 1:many relationship (i.e. a field in a table that is the
* primary key in another table)
* Note that this class has no real way of displaying itself properly,
* so it would usually be inherited and the descendent class used.
* $f = new RadioList("myfield", "Field name");
* $f->connectDB("mytable", array("id", "name"));
* $f->setFormat("id", "%s", array("name"));
* $newentryfield = new TextField("name","");
* $newentryfield->namebase = "newentry-";
* $newentryfield->suppressValidation = 0;
* $f->list->append(array("-1","Create new: "), $newentryfield);
* @subpackage FormsLibrary
/** @var mixed string or array (preferably) that defines the LEFT JOIN */
/** @var string an SQL restriction clause to be used in a WHERE */
/** @var string column for ORDER BY */
/** @var string LIMIT data */
/** @var boolean SELECT DISTINCT */
/** @var boolean list is editable */
/** @var boolean list is extendable by adding new values */
/** @var boolean selected value in list has changed */
/** @var tristate NULL => do not restrict on deleted column, otherwise WHERE deleted = $deleted */
/** @var array the list of choices available */
/** @var integer the number of choices available */
/** @var array the list of appended entries */
/** @var array the list of prepended entries */
* Construct the DBlist object.
* Construct a new DBList object based on:
* - database table ($table)
* - calling for the fields in the array (or scalar) $fields
* - with an SQL restriction (WHERE clause) $restriction
* - ordering the listing by $order
* - using the field $idfield as the control variable in the list
* (i.e. the value='' in a radio list etc)
* - with an SQL LIMIT statement of $limit
* @param string $table the table to be queried for filling
* @param mixed $fields string for the field or array of field names
* @param string $restriction an SQL restriction clause to be used in a WHERE
* @param string $order fields for SQL ORDER clause
* @param string $idfield the field that should be used as the uniquely identifying value
* @param string $limit for LIMIT clause
* @param mixed $join string or array (preferably) that defines the LEFT JOIN
* @param boolean $distinct return only DISTINCT rows (default: false)
* @param boolean $deleted deleted=true/false in SQL; NULL means don't restrict
$order=
'', $idfield=
'id', $limit=
'', $join=
'', $distinct=
false, $deleted=
NULL) {
$this->DBO($table, '', $idfield);
#$this->idfield = $idfield;
$this->join =
array($join=>
"$join.id=${join}id");
* Fill the object from the database using the already initialised
foreach ($fields as $v) {
$aliasfields[] =
is_array($v) ?
"$v[0] AS $v[1]" :
$v;
foreach ($this->join as $k =>
$v) {
$joinSyntax .=
'LEFT JOIN '.
$TABLEPREFIX.
$k.
' AS '.
$k.
' ON '.
$v.
' ';
$restrictions =
($restrictions ?
$restrictions.
' AND ' :
'') .
$this->table.
'.deleted=1 ';
$restrictions =
($restrictions ?
$restrictions.
' AND ' :
'') .
$this->table.
'.deleted<>1 ';
$q =
'SELECT '.
($this->distinct?
'DISTINCT ':
'').
$f
.
' FROM '.
$TABLEPREFIX.
$this->table.
' AS '.
$this->table.
' '
.
($restrictions !=
'' ?
"WHERE $restrictions " :
'')
.
($this->order !=
'' ?
"ORDER BY {$this->order} " :
'')
.($this->limit !=
'' ?
"LIMIT {
$this->limit} " :
'');
//then the SQL query was unsuccessful and we should bail out
while ($g =
db_fetch_array($sql)) {
$this->choicelist[] =
$g; #['key']] = $g['value'];
//if this fill() has been called after extra fields have been prepended
//or appended to the field list, then we need to re-add them as they
//will be lost by this process
* Construct an array suitable for storing the field and the values it takes for later reuse
* @param array $values list of values to be displayed
* @param Field $field Field object associated with these values
function _mkaddedarray($values, $field='') {
for ($i=0; $i < count($values); $i++) {
$a[$this->fields[$i]] =
$values[$i];
$a['_field'] = is_object($field) ? clone($field) : $field;
* Clone the array field structure
* @param array $a field structure array (see _mkaddedarray())
* @return array clone of $a
function _addedclone($a) {
$b['_field'] = is_object($a['_field']) ? clone($a['_field']) : $a['_field'];
* append a special field (such as "Create new:") to the choicelist
* Keep a copy of the field so it can be added again later if
* necessary, and then use a private function to actually do the adding
* @param array $values list of values to be displayed
* @param Field $field (optional) a field class object to be placed next to this entry, if possible
function append($values, $field='') {
//keep a copy of the field so it can be added again after a fill()
* prepend a special field (such as "Create new:") to the choicelist
* Keep a copy of the field so it can be added again later if
* necessary, and then use a private function to actually do the adding
* @param array $values list of values to be displayed
* @param Field $field (optional) a field class object to be placed next to this entry, if possible
function prepend($values, $field='') {
//keep a copy of the field so it can be added again after a fill()
* private functions _append and _prepend that will actually add the field
* to the field list after it has been properly constructed and saved for
* add back in the extra fields that were appended/prepended to the
* choicelist. Use this if they fields are lost due to a fill()
function _reAddExtraFields() {
return "<pre>DBChoiceList:\n".print_r($this->choicelist, true).
"</pre>";
* update the value of the list based on user data:
* - if it is within the range of current values, then take the value
* - if the field contains a new value (and is allowed to) then keep
* an illegal value, mark as being changed, and wait until later for
* the field to be updated
* - if the field contains a new value (and is not allowed to) or an
* out-of-range value, then flag as being invalid
* @param string $newval the (possibly) new value for the field
* @param array ancillary user data (passed on to any appended or prepended fields)
function update($newval, $data) {
$this->log('DBChoiceList update: (changed='.
$this->changed.
', id='.
$this->id.
', newval='.
$newval.
')');
//check to see if the newval is legal (does it exist on our choice list?)
$this->log('('.
$isExisting.
':'.
$v[$this->idfield].
':'.
$newval.
')');
// it is a legal, existing value, so we adopt it
$this->log('isExisting');
//isValid handling done by the Field that inherits it
// then it is a new value and we should accept it
$this->log('isExtending');
// If we are extending the list, then we should have a negative
// number as the current value to trip the creation of the new
// entry later on in sync()
if (isset($v['_field']) && is_object($v['_field'])) {
// else, it's a new value and we should not accept it
$this->errorMessage .=
'<br />'.
T_('Invalid data:').
' '.
$this->longname;
#echo " DBchoiceList::changed=$this->changed<br />";
* sets the current value of the field
* (providing interface to Field object)
#echo "DBchoiceList::set = $value<br/>";
* synchronise with the database
* This also creates the true value for this field if it is undefined
* @return code from statuscodes
* @global string prefix for SQL table names
// If the input isn't valid then bail out straight away
$this->log('not syncing: changed='.
$this->changed);
//echo "Syncing...<br />";
//it's a new record, insert it
$q =
'INSERT '.
$TABLEPREFIX.
$this->table.
' SET '.
$vals;
$sql_result =
db_quiet($q, $this->fatal_sql);
* Returns an SQL assignment clause
* @return string of form name='value'
#echo "This has changed";
if (isset($v['_field'])) {
$vals[] = $v['_field']->name .
"=".
qw($v['_field']->value);
#echo "<pre>"; print_r($this->choicelist); echo "</pre>";
#echo "<pre>"; print_r($this->fields); echo "</pre>";
#echo "<pre>"; print_r($vals); echo "</pre>";
* determine whih values are selected and return them
* @param boolean $returnArray return an array of values
* @return mixed list of selected values (array) or current value (string)
function selectedValue($returnArray=0) {
//echo "H:$this->idfield, $k, $v, $this->id";
foreach ($this->fields as $f) {
return ($returnArray ? $val : implode(' ', $val));
* set which option in the selection list is the default option
* @param string $val default value to use
function setDefault($val) {
//echo "DBChoiceList::setDefault: $val";
if (isset($this->id) ||
$this->id <
0) {
* PHP5 clone statement will perform only a shallow copy of the object. Any subobjects must also be cloned
//print "send in the clones! I'm cloning a ".get_class($this);
//preDump(debug_backtrace());
//preDump($this->appendedfields);
//preDump($this->prependedfields);
// Force a copy of contents of $this->fields array, otherwise the fields will only be references
//print "cloning $k<br />";
if (is_object($f['_field'])) $this->appendedfields[$k]['_field'] =
clone($f['_field']);
//print "cloning $k<br />";
if (is_object($f['_field'])) $this->prependedfields[$k]['_field'] =
clone($f['_field']);
Documentation generated on Tue, 06 Mar 2007 10:01:17 +0000 by phpDocumentor 1.3.0