I am working with a hook_form_alter on a CCK type (for you drupal-ers). I have a field that is normally a select list in my node form. However, in this instance, I want to hide the select list, and populate its value in the form with an SQL query.
Everything was going nicely. I could see that my desired value was showing up in the HTML source, so I knew my query was executing properly. However, when I submit the form, it only inserts the first character of the value. A few of my tests were values of 566, 784, 1004 - the column values were 5,7,1, respectively.
At first I thought it had to be the DB column attributes, but when I removed my form_alter that makes the field hidden and select the value manually, the correct value is inserted?!?
<?php
function addSR_form_service_request_node_form_alter(&$form, $form_state) {
if (arg(0) == 'user' && is_numeric(arg(1))) {
$account = arg(1);
$club = 2589;
$form['field_sr_account'] = array( '#type' => 'hidden',
'#value' => $club
);
}
}
?>
Can anyone see why only the first character would be inserted??
Note: I have tried deleting and recreating the column, using #value & #default_value, and it is still submitting only the first character of the integer. Also, I eliminated the submit handler as a possible cause by removing it, which still resulted in only one character being submitted
More Updates - Still Searching!
Okay, some good questions. Allow me to answer them:
The DB column type is integer(4)
The HTML the hook produces is :
input type="hidden" name="field_sr_account" id="edit-field-sr-account" value="2589"
Latest Update: I think the issue has been narrowed to the structure of the array. When I do var_dump on this field after the form alter has been processed, this is what I get..
[43] => Array
(
[#type] => hidden
[#default_value] => 2589
[#post] => Array
(
)
[#programmed] =>
[#tree] =>
[#parents] => Array
(
[0] => field_sr_account
)
[#array_parents] => Array
(
[0] => field_sr_account
)
[#weight] => 0.016
[#processed] => 1
[#description] =>
[#attributes] => Array
(
)
[#required] =>
[#input] => 1
[#process] => Array
(
[0] => form_expand_ahah
)
[#name] => field_sr_account
[#id] => edit-field-sr-account
[#value] => 2589
[#defaults_loaded] => 1
[#sorted] => 1
)
What is the structure of the field that I can set the form value to. It's gotta be something like what abhaga is suggesting..
Since the field you are trying to change was originally using a select widget, CCK will be looking for $form_state['values']['field_sr_account'][0]['value']. By setting the field to a #hidden type and setting #value, you will get its value in $form_state['values']['field_sr_account']. CCK will try to access the first element of that and end up with the first character of the value.
Updated: The easiest way to achieve what you need would be to do something:
function addSR_form_service_request_node_form_alter(&$form, $form_state) {
if (arg(0) == 'user' && is_numeric(arg(1))) {
$account = arg(1);
$club = 2589;
// Use this property to store the value to restore back
$form['#field_sr_account'] = $club;
$form['field_sr_account'] = array( '#type' => 'hidden','#value' => $club);
}
}
/*in your submit handler, restore the value in the proper format*/
$form_state['values']['field_sr_account'] = array('0' => array('value' => $form['#field_sr_account']));
Old Answer
One way of accomplishing what you are
trying to do is to copy the whole
$form['field_sr_account'] into
$form['#field_sr_account'] and then
provide the value through the SQL
query in the right format in the
submit handler itself.
Ok take a look at http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html#hidden versus http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html#value
It is also recommended you use value instead of hidden. You can find this info on http://api.drupal.org/api/drupal/developer--topics--forms_api.html/6
Also, type hidden is not allowed to have properties your assigning to it so this may be causing a problem. Any usage problems you may be having with the forms API should be answer in those resources as I"m still a little unclear on what you're trying to accomplish... specifically with the submit button.
Old answer:
Ok if I understand this correctly
$club is not being set correctly. If
the first result from your query is
the number your looking for then this
should work.
Try calling
<?php print_r(db_fetch_array($result)) ?>
to get a look at everything returned
from the query.
I'm a little unclear as to what is
being set incorrectly. If it's
#value inside your associated array
then the culprit must be the query.
If #value is being set correctly and
whatever your doing with it later may
be the culprit (not shown here). If
its the values in your $form_state I
don't see that your using $club here
at all.
Also, in your addSR_submit_function
you don't seem to be using the $form
variable, or using $club for anything
except for setting the message which
appears at the top of the page your on
when it's called.
I may need some further clarification
as to what exactly is going wrong.
Also, when you're calling
drupal_set_message function, are you
just doing this for debugging
purposes?
Shouldn't you check
drupal_set_message($form_state['values']['field_sr_account']);
instead of
drupal_set_message($club);
in addSR_submit_function ?
OK, just a quess: not sure what type db_result returns for your query, may be it has something to do with types conversions? So this is to make sure value is int.
'#value' => (int)$club
cinqoTimo, Out of curiosity what kind of CCK field is this? Is it a Integer, Decimal, Float? and do you have any special parameters on that field not normally on by default? What is the column type in the db?
Can you post the html output of the form. That might give a clue as to what might be going on.
Are you using any javascript to edit any values for this field?
Have you tried outputting the value results from addSR_form_service_request_node_submit hook? Any difference there.
Sorry for all the questions. Just thinking out loud as it seems you have covered most of your bases.
Related
I am working with an array of tokens for an HTML template. Two of them ('{SYS_MENU}' and '{SUB_MENU}') are used to generate control buttons for the web application. Right now the buttons show up on the login page before the user's credential's are validated, and I need to change the code so that the buttons are hidden until after users login and reach the main menu. When someone types the http: address into their browser and arrives at the login page the system starts a session for them in the MySQL sessions table with USER_ID = 0. After they login the USER_ID changes to whatever number was assigned to them at initial registration (Example: USER_ID = 54), and after they logout at the end of the session back to 0. Tying this constant to the buttons seems like the best solution and I have found it to work in the past under similar circumstances.
Here is the original array:
$template_vars = array(
'{LANG_DIR}' => $lang_text_dir,
'{TITLE}' => theme_page_title($section),
'{CHARSET}' => $charset,
'{META}' => $meta,
'{GAL_NAME}' => $CONFIG['gallery_name'],
'{GAL_DESCRIPTION}' => $CONFIG['gallery_description'],
'{SYS_MENU}' => theme_main_menu('sys_menu'),
'{SUB_MENU}' => theme_main_menu('sub_menu'),
'{ADMIN_MENU}' => theme_admin_mode_menu(),
'{CUSTOM_HEADER}' => $custom_header,
'{JAVASCRIPT}' => theme_javascript_head(),
'{MESSAGE_BLOCK}' => theme_display_message_block(),
);
The first thing I did was to work with the references directly in the HTML template. I saw an example on w3schools that made it look like you could just type a PHP script into HTML and have it resolve. That didn't do anything except echo a bunch of text randomly into the page. I then found another citation that said you had to activate the PHP with an .HTACCESS entry before it would work directly in HTML. But that didn't close the deal either.
I know that changing '{SYS_MENU}' and '{SUB_MENU}' values in the array to => "", produces the results that I want (I.E. make the menu buttons disappear). So my next thought was I'll create an IF statement that returns two versions of the array based on circumstances, something like:
if(USER_ID != 0)
{
return $template_vars = //FIRST VERSION OF ARRAY WITH FULL VALUES//
}
else
{
return $template_vars = //SECOND VERSION OF ARRAY WITH ONLY => ""//
}
But all that did was cause the application load to terminate at a white screen with no error feedback.
My most recent attempt came from something I read here on Stack Overflow. I know that you cannot put IF statements into an array. But the article at this link described a workaround:
If statement within an array declaration ...is that possible?
So I rewrote the array as follows:
template_vars = array(
'{LANG_DIR}' => $lang_text_dir,
'{TITLE}' => theme_page_title($section),
'{CHARSET}' => $charset,
'{META}' => $meta,
'{GAL_NAME}' => $CONFIG['gallery_name'],
'{GAL_DESCRIPTION}' => $CONFIG['gallery_description'],
'{SYS_MENU}' => ('USER_ID != 0' ? theme_main_menu('sys_menu') : ""),
'{SUB_MENU}' => ('USER_ID != 0' ? theme_main_menu('sub_menu') : ""),
'{ADMIN_MENU}' => theme_admin_mode_menu(),
'{CUSTOM_HEADER}' => $custom_header,
'{JAVASCRIPT}' => theme_javascript_head(),
'{MESSAGE_BLOCK}' => theme_display_message_block(),
);
But that seems to have no effect at all. The application doesn't crash but the buttons are static whether you are logged in or logged out.
My question is: What am I missing? I can see that this is possible. But I've been trying things for a day and a half and just seem to be dancing around the solution. Your thoughts would be greatly appreciated.
The problem here is that you are calling return. With a global include file like this there is not context to return to so the application terminates. What you want to do is just assign the variables.
if(USER_ID != 0)
{
$template_vars = //FIRST VERSION OF ARRAY WITH FULL VALUES//
}
else
{
$template_vars = //SECOND VERSION OF ARRAY WITH ONLY => ""//
}
I have created a light Model Manager for LDAP over PHP's API to ease object managements from Active Directory.
Everything runs fine but I have a problem when updating multi valued attributes even if I change all the values, the transaction fails with «Type or value exists» error and the attribute is not changed in the database.
The test case I am using is to change de multi valued "description" field for a user. If I add new values or change the whole array of values, the transaction always fail.
The part of the code is the following:
if (count($mod_attr) > 0)
{
$ret = #ldap_mod_replace($this->getHandler(), $dn, $mod_attr);
if ($ret === false)
{ $this->log(sprintf("LDAP ERROR '%s' -- Modifying {%s}.", ldap_error($this->getHandler()), print_r($mod_attr, true)), \SlapOM\LoggerInterface::LOGLEVEL_CRITICAL);
throw new LdapException(sprintf("Error while MODIFYING values <pre>%s</pre> in dn='%s'.", print_r($mod_attr, true), $dn), $this->getHandler(), $this->error);
}
$this->log(sprintf("Changing attribute {%s}.", join(', ', array_keys($mod_attr))));
}
The complete code can be found [here on github](https://github.com/chanmix51/SlapOM/blob/master/lib/SlapOM/Connection.php#L115 [github]).
The logs show the following lines:
2013-06-04 10:39:54 | => MODIFY dn='CN=HUBERT Gregoire,OU=...
2013-06-04 10:39:54 | => LDAP ERROR 'Type or value exists' -- Modifying {Array
(
[description] => Array
(
[0] => Description 2
[1] => Description 3
)
)}
Even if the preceding values were ["description" => ['Description 1']]. Is there something I am not getting or doing wrong ?
The answer is short: «Description is not a multi valued field». As usual, the error message was so confusing, it lead me to spend hours on the wrong problem.
In short: the LDAP error 20 «Type or value exists» can be either you are trying to insert twice the same values in a multi valued field or you are trying to insert several values in a single valued field.
I have created a form in which i embed another form. My question is about this embedded form - I'm using a sfWidgetFormDoctrineChoice widget with option multiple set to true. The code for this embedded form's configure method:
public function configure()
{
unset($this['prerequisite_id']);
$this->setWidget('prerequisite_id', new sfWidgetFormDoctrineChoice(array(
'model' => 'Stage',
'query' => Doctrine_Query::create()->select('s.id, s.name')->from('Stage s')->where('s.workflow_id = ?', $this->getOption('workflow_id') ),
'multiple' => true
)));
$this->setValidator('prerequisite_id', new sfValidatorDoctrineChoice(array(
'model' => 'Stage',
'multiple' => true,
'query' => Doctrine_Query::create()->select('s.id, s.name')->from('Stage s')->where('s.workflow_id = ?', $this->getOption('workflow_id') ),
'column' => 'id'
)));
}
I unset the prerequisite_id field because it is included in the base form, but I want it to be a multiple select.
Now, when I added the validator, everything seems to work (it passes the validation), but it seems like it has problems saving the records if there is more than one selection sent.
I get this PHP warning after submitting the form:
Warning: strlen() expects parameter 1 to be string, array given in
D:\Development\www\flow_dms\lib\vendor\symfony\lib\plugins\sfDoctrinePlugin\lib\database\sfDoctrineConnectionProfiler.class.php
on line 198
and more - I know, why - in symfony's debug mode I can see the following in the stack trace:
at Doctrine_Connection->exec('INSERT INTO stage_has_prerequisites
(prerequisite_id, stage_id) VALUES (?, ?)', array(array('12', '79'),
'103'))
So, what Symfony does is send to Doctrine an array of choices - and as I see in the debug sql query, Doctrine cannot render the query correctly.
Any ideas how to fix that? I would need to have two queries generated for two choices:
INSERT INTO stage_has_prerequisites (prerequisite_id, stage_id) VALUES (12, 103);
INSERT INTO stage_has_prerequisites (prerequisite_id, stage_id) VALUES (79, 103);
stage_id is always the same (I mean, it's set outside this form by the form in which it is embedded).
I have spend 4 hours on the problem already, so maybe someone is able to provide some help.
Well, I seem to have found a solution (albeit not the best one, I guess). Hopefully it'll be helpful to somebody.
Finally, after much thinking, I have concluded that if the problem comes from the Doctrine_Record not being able to save the record if it encounters an array instead of a single value, then the easiest solution would be to overwrite the save() method of the Doctrine_Record. And that's what I did:
class StageHasPrerequisites extends BaseStageHasPrerequisites
{
public function save(Doctrine_Connection $conn = null)
{
if( is_array( $this->getPrerequisiteId() ) )
{
foreach( $this->getPrerequisiteId() as $prerequisite_id )
{
$obj = new StageHasPrerequisites();
$obj->setPrerequisiteId( $prerequisite_id );
$obj->setStageId( $this->getStageId() );
$obj->save();
}
}
else
{
parent::save($conn);
}
}
(...)
}
So now if it encounters an array instead of a single value, it just creates a temporary object and saves it for each of this array's values.
Not an elegant solution, definitely, but it works (keep in mind that it is written for the specific structure of the data and it's just the effect of my methodology, namely See What's Wrong In The Debug Mode And Then Try To Correct It Any Way Possible).
I'm having an annoying problem. I'm trying to find out what fields of a form were changed, and then insert that into a table. I managed to var_dump in doUpdateObjectas shown in the following
public function doUpdateObject($values)
{
parent::doUpdateObject($values);
var_dump($this->getObject()->getModified(false));
var_dump($this->getObject()->getModified(true));
}
And it seems like $this->getObject()->getModified seems to work in giving me both before and after values by setting it to either true or false.
The problem that I'm facing right now is that, some how, sfWidgetFormSelect seems to be saving one of my fields as a string. before saving, that exact same field was an int. (I got this idea by var_dump both before and after).
Here is what the results on both var dumps showed:
array(1) {["annoying_field"]=> int(3)} array(1) {["annoying_field"]=>string(1)"3"}
This seems to cause doctrine to think that this is a modification and thus gives a false positive.
In my base form, I have
under $this->getWidgets()
'annoying_field' => new sfWidgetFormInputText(),
under $this->setValidators
'annoying_field' => new sfValidatorInteger(array('required' => false)),
and lastly in my configured Form.class.php I have reconfigured the file as such:
$this->widgetSchema['annoying_field'] = new sfWidgetFormSelect(array('choices' => $statuses));
statuses is an array containing values like {""a", "b", "c", "d"}
and I just want the index of the status to be stored in the database.
And also how can I insert the changes into another database table? let's say my Log table?
Any ideas and advice as to why this is happen is appreciated, I've been trying to figure it out and browsing google for various keywords with no avail.
Thanks!
Edit:
ok so I created another field, integer in my schema just for testing.
I created an entry, saved it, and edited it.
this time the same thing happened!
first if you what the status_id to be saved in the database, you should define your status array like this:
{1 => "a", 2 => "b", 3 => "c", 4 => "d"}
So that way he know that 1 should be rendered like "a" and so on. Then, when saving, only the index should be saved.
About saving in another database, my advise is to modify the doSave method defined by the Form class yo match your needs. I only know how Propel deals with it, maybe this could help:
the doSave method dose something like this:
protected function doSave($con = null)
{
if (null === $con)
{
$con = $this->getConnection();
}
$old = $this->getObject()->getModifiedValues($this);//Define this
$new_object = new Log($old);//Create a new log entry
$new_object->save($con));//save it!
$this->updateObject();
$this->getObject()->save($con);
// embedded forms
$this->saveEmbeddedForms($con);
}
Hope this helps!
Edit:
This is an example extracted from a model in one of my applications and its working ok:
Schema:
[...]
funding_source_id:
type: integer
required: true
[...]
Form:
$this->setWidget('funding_source_id', new sfWidgetFormChoice(array(
'choices' => array(1 => 'asdads', 2 => '123123123' , 3 => 'asd23qsdf'),
)));
$this->setValidator('funding_source_id', new sfValidatorChoice(array(
'choices' => array(1 => 'asdads', 2 => '123123123' , 3 => 'asd23qsdf'),
'required' => true
)));
About the log thing, that could be quite more complex, you should read the current implementation of the doSave method in the base form class, currently sfFomrObject on Symfony1.4., and when and how it delegates object dealing with modified values.
Okay,
It turns out I forgot to do a custom validator to use the array key instead.
I have a PHP function that returns an array. This is the output of print_r($myArray):
Array (
[id] => 8166
[customer_id] => 73
[nickname] => AnnieB
[name] => Anastasia Beaverhausen
[email] => annieb#annieb.com
[phone] => 555-555-5555
[company] => Annie B's
[address1] => 123 Main Street
[address2] => Apartment 555
[city] => Chicago
[state] => IL
[zip] => 55555
[billing] => 1
[residence] => 0
[token] =>
[verified] => 1 )
I should be able to access any of the members by saying something like $myArray['city'], correct? I know I've done this in the past, but it keeps returning an empty string, even when there is a value in the city field.
Any ideas?
==================MORE CODE POSTED PER REQUESTS=============================
I'm using this in Joomla, so there are a few lines that are specific to Joomla. The end purpose of this code is to populate a dropdown list with addresses from a database; the option values contain an imploded string of all column values (to be accessed via javascript later) and the option text is a single field. Here's the code that creates the dropdown:
foreach (getAddresses($AcctID) as $id => $info) {
print_r($info);
$nickName = $info[2];
error_log("nickname=".$nickName);
$infoStr = implode("|", $info);
$addressOptions .= "<option value=\"{$infoStr}\">$nickName</option>";
}
The getAddresses function is here (this is working correctly):
function getAddresses($AcctID) {
$db =& JFactory::getDBO();
$query = "select * from jos_customers_addresses where customer_id = ".$db->quote($AcctID);
$db->setQuery($query);
if (!$db->query()) error_log($db->stderr());
if (!$db->getNumRows())
return false;
else
return $db->loadAssocList();
}
The print_r($info) line is what is returning the array I originally posted. The next two lines are the ones giving me problems:
$nickName = $info[2];
error_log("nickname=".$nickName);
I've also tried $nickName = $info['nickname'] and gotten the same result - no value, even though there's obviously a value in the print_r, and the value does come through correctly in the code generated by the implode line. If you can find someplace between those two lines where I'm overwriting my variable, or whatever, please point it out to me, because I'm clueless as to why I can't get a handle on this value.
I should be able to access any of the
members by saying something like
$myArray['city'], correct?
Yes, that's correct.
I know I've done this in the past, but
it keeps returning an empty string,
even when there is a value in the city
field.
If nothing is showing up, there's probably not a value there, which as the comments said, is most likely a bug in your code (something overwriting that key). To be sure there's nothing there, instead of echo $myArray['city'] try var_dump($myArray['city']) -- this will tell you if it's an empty string (string(0) "") or not set at all (NULL)
Take your print_r($myArray) and put it immediately before the statement where you use $myArray['city']. is the 'city' key still set? If so, double check to make sure you don't have a typo... capitalization matters! If it's not still set, move the print_r($myArray) up a few lines and repeat until you find what's unsetting $myArray['city']
...Or just post more code ;-)
EDIT: Did $info[2] need to be $info['city']?