Source for file joindata.php
Documentation is available at joindata.php
* an object that manages data related by an SQL JOIN but pretends to be a single form field.
* @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 'field.php';
/** database row manipulation object */
require_once 'dbrow.php';
/** connect to database */
require_once 'inc/db.php';
* an object that manages data related by an SQL JOIN but pretends to be a single form field.
* If the element in the table is a selection list then the setup will be
* We respect the 'field' interface while overriding pretty much all of it.
* Primitive class for managing join data. Can be used on its own to just
* join data or with a selection lists class to make a join table.
* This may be used to determine the choices
* that a user is permitted to select (e.g. dropdown list or radio buttons)
* Used in a many:many or many:1 relationships (i.e. a field in a
* table that is the listed in a join table
* $f = new JoinData('jointable', 'id1', $table1_key, 'fieldname', 'label1');
* $f2 = new DropList('id2', 'label2');
* $f2->connectDB('table2', array('id', 'name'));
* $f2->list->prepend(array('-1','(none)'));
* $f2->setFormat('id', '%s', array('name'), ' (%s)', array('longname'));
* $f3 = new TextField('field3', '');
* $f->addElement($f3, 'sum_is_100');
* $f->joinSetup('id2', array('total' => 3));
* @subpackage FormsLibrary
/** @var string name of the join table (table has columns of form (LeftID, RightID) to join Left and Right tables */
/** @var string column name in the join table for the column with keys/Ids from the left table */
/** @var string value of the left column ID that we are matching */
/** @var string column name in the join table for the column with keys/Ids from the right table */
/** @var DBRow prototype DBRow object that is replicated for each entry in the join table (1:many join) */
/** @var array list of DBRow objects for each row returned in a 1:many join */
/** @var string number of columns that this field should span in the table */
/** @var array formatting control arguments (e.g. maximum number permitted in 1:many) */
/** @var integer number of rows in the join */
/** @var array list of columns to return when the containing object asks for the SQL column=value sequence */
/** @var array list of functions that should be applied to the group of results collectively to test validity */
/** @var boolean SQL errors should be fatal (die()) */
* Create a new joindata object
* @param string $jointable see $this->joinTable
* @param string $jtLeftIDCol see $this->jtLeftIDCol
* @param string $jtLeftID see $this->jtLeftID
* @param string $name the name of the field (db name, and html field name
* @param string $description used in the html title or longdesc for the field
function JoinData($joinTable, $jtLeftIDCol, $jtLeftID,
$name, $description=
'') {
$this->Field($name, '', $description);
$this->protoRow =
new DBRow($joinTable, $jtLeftID, $jtLeftIDCol);
$field =
new Field($jtLeftIDCol);
$field->defaultValue =
$jtLeftID;
* Connect the join table and fill from the database
* @param string $jtRightIDCol see $this->jtRightIDCol
* @param mixed $format see $this->format (string is converted to array)
function joinSetup($jtRightIDCol, $format=
'') {
* Calculate the maximum number of rows to display (e.g. including spares)
if (isset
($this->format['total'])) {
if (isset
($this->format['minspare'])) {
if (isset
($this->format['matrix'])) {
* add a field to the join table
* Field will appear in each row returned from the join table
* @param Field $field the field to be added
* @param string $groupValidTest data validation routine for this field
function addElement($field, $groupValidTest=
NULL) {
* Create a new row from the protorow for storing data
* @param integer $rowNum number of this row (used as unique identifier in the namebase)
#echo "NAMEBASE={$this->namebase}";
#echo "NAME={$this->name}";
#for ($i=0; $i<=$rowNum; $i++) {
# echo "NB = ". $this->rows[$i]->namebase."<br />";
* Fill from the database one row at a time
$this->log('Extending rows from '.
$oldnumber.
' to '.
$this->number);
for ($i=
$oldnumber; $i <
$this->number; $i++
) {
$this->rows[$i]->recNum =
1;
$this->rows[$i]->recStart =
$i;
$this->log('This row flagged with insertRow '.
$this->rows[$i]->insertRow);
if ($this->rows[$i]->insertRow) {
$this->rows[$i]->fillWithDefaults();
//check how many fields we need to have (again) as we might have to show more this time around.
#$errorclass = ($this->isValid ? '' : "class='inputerror'");
for ($i=
0; $i<
$this->number; $i++
) {
$t .=
"<tr $errorclass><td colspan='$this->colspan'>\n";
$t .=
$this->rows[$i]->displayInTable(2);
for ($col=
0; $col<
$cols-
2; $col++
) {
//check how many fields we need to have (again) as we might have to show more this time around.
//$cols += $this->colspan;
$t =
"<tr><td colspan='$cols'>{$this->description}</
td></
tr>\n
";
//preDump(debug_backtrace());
$t .=
"<input type='hidden' name='{
$this->name}'
value='
".xssqw($this->value).
" />";
for ($i=0; $i < $this->number; $i++
) {
$rowchanged = $this->rows[$i]->update($data);
$this->log('JoinData-Row '.
$i.
' has changed.');
foreach (array_keys($this->rows[$i]->fields) as $k) {
#$this->rows[$i]->fields[$this->jtRightIDCol]->changed = $rowchanged;
#if ($v->name != $this->jtRightIDCol && $v->name != $this->jtLeftIDCol) {
$this->rows[$i]->fields[$k]->changed =
$rowchanged;
$this->log('Overall JoinData row changed='.
$this->changed);
* Count the number of rows in the join table so we know how many to retrieve
* @return integer number of rows found
function _countRowsInJoin() {
$this->log('Found '.
$g[0].
' rows currently in join');
* Trip the complex field within this object to sync()
* This allows the object to then know our actual value (at last) -- this has to be
* delayed for as long as possible as an INSERT might be needed before the value of the
* selection is actually known, but that shouldn't be done until all the data has passed
* @return string sql name=value sequence
function sqlSetStr($name='', $force=false) {
#echo "JoinData::sqlSetStr";
//We return an empty string as this is only a join table entry,
//so it has no representation within the row itself.
// then we can return the value of the first row (any more doesn't make sense)
$aliasfield = current($f);
$t[] = $this->rows[0]->fields[$realfield]->sqlSetStr($aliasfield);
$t[] = $this->rows[0]->fields[$f]->sqlSetStr();
* synchronise the join table
for ($i=0; $i < $this->number; $i++
) {
#echo "before sync row $i oob='".$this->oob_status."' ";
//preDump($this->rows[$i]->fields[$this->jtRightIDCol]);
if ($this->rows[$i]->fields[$this->jtRightIDCol]->value !==
'' // damned PHP '' == 0
//then this row is to be deleted...
$this->log('JoinData::_joinSync(): Syncing row '.
$i);
// preDump($this->rows[$i]);
#echo " after sync row $i oob='".$this->oob_status."'";
* override the isValid method of the Field class, using the
* checkValid method of each member row completed as well as
* cross checks on other fields.
* @return boolean data is valid
$this->log('Check JoinData validity: '.
$this->name);
for ($i=
0; $i <
$this->number; $i++
) {
#echo "val". $this->rows[$i]->fields[$this->jtRightIDCol]->value.";";
//$this->log('Row: '.$i);
$this->rows[$i]->isValid =
1;
if ($this->rows[$i]->fields[$this->jtRightIDCol]->value !==
'' // damned PHP '' == 0
&&
$this->rows[$i]->changed) {
// this row will be deleted to mark it valid in the mean time
$this->rows[$i]->isValid =
1;
&&
$this->rows[$i]->changed) {
//this row will be sync'd against the database, so check its validity
//$this->log('Checking valid for row: '.$i);
//echo "JoinData::isValid = '$this->isValid'";
//echo "JoinData::isValid[$i] = '".$this->rows[$i]->isValid."'";
//now we need to check the validity of sets of data (e.g. sum of the same
//field across the different rows.
foreach ($this->rows[0]->fields as $k =>
$f) {
for ($i=0; $i < $this->number; $i++
) {
$allvals[] = $this->rows[$i]->fields[$k]->value;
for ($i=0; $i < $this->number; $i++
) {
$this->rows[$i]->fields[$k]->isValid =
0;
//echo "JoinData::isValid = '$this->isValid'";
* Change the Id value of each row
function idChange($newId) {
for ($i=0; $i < $this->number; $i++
) {
$this->rows[$i]->setId($newId);
* Set the name base of the rows
function setNamebase($namebase='') {
for ($i=0; $i < $this->number; $i++
) {
$this->rows[$i]->setNamebase($namebase);
$this->protoRow->setNamebase($namebase);
* set whether each row is editable
function setEditable($editable=false) {
for ($i=0; $i < $this->number; $i++
) {
$this->rows[$i]->setEditable($editable);
$this->protoRow->setEditable($editable);
Documentation generated on Tue, 06 Mar 2007 10:01:42 +0000 by phpDocumentor 1.3.0