PEAR is archived and read-only

This mirror preserves historical PEAR package releases and metadata so existing references remain available.

Home » Database » DB_DataObject_FormBuilder » Bug #3469

enum fields don't show proper value

Details

Submitted2005-02-14 18:19 UTC
Fromandrew dot clark at ucsb dot edu
Assignedjustinpatrin
StatusClosed
PackageDB_DataObject_FormBuilder
PHP Version4.3.10
OSFreeBSD 4.10
Roadmaps(Not assigned)

Comments

[2005-02-14 18:19 UTC] andrew dot clark at ucsb dot edu

Description:
------------
Refer to bug #3124

Enum fields, whether frozen or not, do not display their proper value from the database. The sample code in bug #3124 should reproduce the problem.

[2005-02-15 20:04 UTC] andrew dot clark at ucsb dot edu

Sure thing.
Here's the DB table:

CREATE TABLE net_contact (
net_contact_id int(16) unsigned NOT NULL auto_increment,
net_id int(16) unsigned NOT NULL default '0',
contact_id int(16) unsigned NOT NULL default '0',
role enum('primary','secondary','security','financial') NOT NULL default 'secondary',
last_modified timestamp(14) NOT NULL,
last_verified datetime default NULL,
PRIMARY KEY (net_contact_id),
UNIQUE KEY net_id (net_id,contact_id,role)
) TYPE=MyISAM;

Here's the DO code:
<?php
/**
* Table Definition for net_contact
*/
require_once 'DB/DataObject.php';

class DataObjects_Net_contact extends DB_DataObject
{

###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */

var $__table = 'net_contact'; // table name
var $net_contact_id; // int(16) not_null primary_key unsigned
var $net_id; // int(16) not_null unsigned
var $contact_id; // int(16) not_null unsigned
var $role; // string(9) enum
var $last_modified; // timestamp(14) not_null unsigned zerofill timestamp
var $last_verified; // timestamp(14) not_null unsigned zerofill

/* ZE2 compatibility trick*/
function __clone() { return $this;}

/* Static get */
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('DataObjects_Net_contact',$k,$v); }

/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE

var $fb_enumFields = array('role');

var $fb_enumOptions = array('role' =>
array('primary', 'secondary', 'security', 'financial')
);

// var $fb_selectAddEmpty = array('role');

/*
* workaround for improper enum option handling
* in DataObject FormBuilder
*/
/*
function preGenerateForm(&$fb) {
$role_options = array(
null => null,
'primary' => 'primary', 'secondary' => 'secondary',
'security' => 'security' , 'financial' => 'financial'
);

$this->fb_preDefElements['role'] = HTML_QuickForm::createElement(
'select', $fb->elementNamePrefix .'role' .$fb->elementNamePostfix,
'Role', $role_options
);
}
*/

}

?>

here's the implementing code:

<?php
require_once 'include/config.php';
require_once 'DB/DataObject/FormBuilder.php';

DB_DataObject::debugLevel(0);

$self =& DB_DataObject::factory('net_contact');

if (PEAR::isError($self)) {
die ( $self->getMessage() );
}

$self->get(7);

$builder =& DB_DataObject_FormBuilder::create($self);

$form =& $builder->getForm();
$form->freeze();

echo $form->toHtml();

?>

If the form is not frozen, the enum field has nothing selected (though it does show the options). If it is frozen, it always shows the first enum option (primary).

I notice if I remove my fb_enumOptions code, it seems to work...

Here's the relevant row from the db:
+----------------+--------+------------+-----------+----------------+---------------+
| net_contact_id | net_id | contact_id | role | last_modified | last_verified |
+----------------+--------+------------+-----------+----------------+---------------+
| 7 | 205 | 214 | secondary | 20050126165246 | NULL |
+----------------+--------+------------+-----------+----------------+---------------+

[2005-02-16 00:34 UTC] andrew dot clark at ucsb dot edu

Fix verified. Thanks!
Is setting enumOptions now optional, that is, is DB_DataObject_FormBuilder now able to figure out the enum values on its own?

[2005-04-17 00:49 UTC] vtamara at pasosdejesus dot org

Good evening in the Lord

In my humble opinion, this fix reduces functionality.

In my code I was relying on the difference between
keys and values in fb_enumOptions, for example with a
field tipo_ubicaicion of type CHAR(1) I had:

var $fb_enumOptions = array('tipo_ubicacion' => array('S' =>
'Sin Información', 'R' => 'Rural',
'U' => 'Urbano', 'A' => 'Ambos' ),
...

To show human readable messages in the interface while
maintaining just one letter in the database (I used this
in several tables).

Now I have to implement a callback for each table where
I want this feature:

class DataObjects_Caso extends DB_DataObject
{
...
var $fb_enumOptions = array('tipo_ubicacion' => array('S' =>
'Sin Información', 'R' => 'Rural',
'U' => 'Urbano', 'A' => 'Ambos' ),
...
function enumCallback($table, $key) {
return $this->es_enumOptions[$key];
}
...

function preGenerateForm( &$formbuild ) {
$formbuild->enumOptionsCallback=array($this,
"enumCallback");
...

Wasn't it better to fix the documentation? I think
that the problem in the bug report could be solved
also by replacing:

var $fb_enumOptions = array('role' =>
array('primary', 'secondary', 'security', 'financial')
);

with

var $fb_enumOptions = array('role' =>
array('primary'=>'primary', 'secondary'=>'secondary', 'security'=>'security', 'financial'=>'financial')
);

Best regards. God illuminate us.
Vladimir Támara

[2005-04-19 07:25 UTC] michael at baselinesols dot com

I tend to agree with vtamara on this one - while for the bulk of cases, you will have a 'value' => 'value' mapping for enums, there are certainly cases where you'd want the description to be more verbose (and indeed descriptive) than the value. It would also be useful for supporting databases that don't have a native ENUM type, where you must emulate it.

A simple way to keep the current functionality, but still allow for more complex mappings would be to check if the keys of the $options array are sequential and start at 0, ie something like this:

if (array_keys($options) == range(0, count($options)-1)) ...

If true, then assume it's an enum options array of the type array('option1', 'option2', 'option3') - if not, then assume it's of type array('AM' => 'Morning', 'PM' => 'Afternoon) and use the keys accordingly.

The only time this won't work is when you *need* consecutive numeric indices starting at 0, ie:

array('0' => 'Low Priority', '1' => 'Medium Priority')

However, if the order isn't *too* important, then this could be re-expressed as:

array('1' => 'Medium Priority', '0' => 'Low Priority')

Arguably the best way would be to have a config variable to specify whether the options array should keep its keys or not, but this would require a little more effort (though not much).

[2005-04-19 07:32 UTC] michael at baselinesols dot com

Oh yeah - forgot to add, there's something that kinda smells bad around lines 1279-1281 of version 1.151 of FormBuilder.php. Currently it looks like this:

foreach ($options as $option) {
$element =& $this->_createRadioButtons($key, $options); }

It works... but the foreach loop does nothing except waste cycles AFAICS. I think it should just be:

$element =& $this->_createRadioButtons($key, $options);

[2005-04-28 23:29 UTC] michael at baselinesols dot com

Er... but PHP converts integer strings into integers when used as array keys, ie array('0'=>'a') === array(0=>'a') (see http://www.php.net/manual/en/language.types.array.php), so this approach won't work. That's why I had proposed this method:

if (array_keys($options) == range(0, count($options)-1))

Then, if you jumble up the keys, even though they're ints, it will still differentiate. Or you can use something like array('00'=>'a', '01'=>'b'), as this representation will not be converted (but you may need to convert them to ints explicitly when processing the form).

[2005-05-18 01:35 UTC] michael at baselinesols dot com

Perfect - your fix in 0.15.0 (which I think reverts to the old behaviour) is the right one IMHO :-) Even though it may require a little more coding for some people, I feel it's the best way to get customised behaviour.

In PHP 5, you can use $enums = array_combine($enums, $enums) to create an array where the keys are the same as the values - for those that can't be bothered listing the keys with the values.