I have an issue while displaying several forms of the same model on the same page.
The problem is that with the NameFormat, the fields have the same ID :
$this->widgetSchema->setNameFormat('display[%s]');
Will display
<form class="update_display_form" id="update_display_0" action="/iperf/web/frontend_dev.php/update_display" method="post">
<input type="checkbox" name="display[displayed]" checked="checked" id="display_displayed" />
<label for="display_displayed">test</label>
</form>
<form class="update_display_form" id="update_display_1" action="/iperf/web/frontend_dev.php/update_display" method="post">
<input type="checkbox" name="display[displayed]" checked="checked" id="display_displayed" />
<label for="display_displayed">truc</label>
</form>
And if you click on the second label, it will activate the first checkbox
So I thought I could use the object id to make them unique :
$this->widgetSchema->setNameFormat('display'.$this->getObject()->getId().'[%s]');
But then I can not process the request, since I don't know the name of the parameters.
The best option I found was to set an ID :
$this->widgetSchema['displayed']->setAttributes(array("id" => "display".$this->getObject()->getId() ));
but then I totally loose the connections between the label and the checkbox.
The problem would be solved if I could change the "for" attribute of my label. Does somebody know how to do that ? Or any other option ?
Here's an idea... push a variable to the form class from your action for setting a different name format dynamically:
In your action:
$this->form_A = new displayForm(array(),array('form_id' = 'A')); // pass a form id
$this->form_B = new displayForm(array(),array('form_id' = 'B'));
$this->form_C = new displayForm(array(),array('form_id' = 'C'));
In your form class:
$form_id = $this->getOption('form_id'); // get the passed value
$this->widgetSchema->setNameFormat('display'.$form_id.'[%s]'); // stick it into the name
It's ugly but I'm sure you can come up with something cleaner...
Conflicting inter-form checkbox/label interactions is caused by tag's id/for attributes not by their name attributes.
So there is no need to modify form's widget name format and thus having problem reading submitted data from request object (either by passing request key as form url parameter/hidden input or by looping all form name combinations created in the layout for each form and finding a matching one).
sfForm class has sfWidgetFormSchema::setIdFormat() method for that.
// Creating form instances
$formA = new sfForm();
$formA->getWidgetSchema()->setIdFormat( '%s1' );
$formA->getWidgetSchema()->setNameFormat( 'display' );
... // configure the form
$formB = new sfForm();
$formB->getWidgetSchema()->setIdFormat( '%s2' );
$formB->getWidgetSchema()->setNameFormat( 'display' );
... // configure the form
$formC = new sfForm();
$formC->getWidgetSchema()->setIdFormat( '%s3' );
$formC->getWidgetSchema()->setNameFormat( 'display' );
... // configure the form
// Processing a request data
$form = new sfForm();
... // configure the form
$_formNameRequestKey = $form->getName();
if( $request->hasParameter( $_formNameRequestKey ) ) {
$form->bind( $request->getParameter( $_formNameRequestKey ) );
}
... or just ...
if( $request->hasParameter( 'display' ) ) {
$form->bind( $request->getParameter( 'display' ) );
}
Related
I'm trying to set a new value for the first_name for a user on woocommerce, i want to do this using the 'CRUD Objects in 3.0' present in the last documentation of woocommerce 3.0.
Só i'm definig the variable:
$wc_current_user = WC()->customer;
This return an instance of the class WC_Customer with has an array of $data with data about customer like $first_name, $last_name, $email, $billing_address array and so on...
i'm trying to rewrite the edit-account.php form and want to submit this data on this object, he provide the getters and setters to do this, but seems the setter ins't working, he is not saiving the data.
I'm doing this:
I have a form with takes the first name from the user, this is working fine, i'm using the ->get_first_name and is working fine.
<form class="woocommerce-account-information" action="" method="post">
<label>First Name</label>
<input type="text" name="first_name" value="<?php echo
$wc_current_user->get_first_name()?>"/>
<button type="submit">SAVE</button>
</form>
The Problema is here, when i try to submit this data using a setter, which in this case is 'object -> set_first_name' and 'object->save()', nothing happens, someone can help me?
Here is my code:
if( isset($_POST['first_name'] ) ){
$wc_current_user->set_first_name($_POST['first_name']);
$wc_current_user->save();
}
//THIS ^ DON'T WORK, do you know what is wrong?
I'm interested in knowing both the old and the new method, if anyone can help me, it will be a great help. Thank you!
You're using the correct method to set the user's first name.
set_first_name() won't permanently save a value on its own. When you've set all the properties you wish to update you need to call the save() method.
if ( isset( $_POST['first_name'] ) ) {
$wc_current_user->set_first_name( $_POST['first_name'] );
$wc_current_user->save();
}
https://woocommerce.wordpress.com/2016/10/27/the-new-crud-classes-in-woocommerce-2-7/
https://github.com/woocommerce/woocommerce/wiki/CRUD-Objects-in-3.0
I find a solution for this problem, when you use object like this you need to use the $object-save() method that Nathan has said plusthe $object->apply_changes(); to submit replace the data on data-base:
public function apply_changes() {
$this->data = array_replace_recursive( $this->data, $this->changes );
$this->changes = array();
}
My working code looks like this:
$wc_current_user = WC()->customer;
if ( isset($_POST['first_name']) ) {
$wc_current_user->set_first_name($_POST['first_name']);
$wc_current_user->save();
$wc_current_user->apply_changes();
}
My question is whether I should use set_value() at all to re-populate a form. It might seem odd to say that, however I am creating a shared controller function and view which can be used to either add a new record or edit an existing one. It seems to make sense to do this since the functionality is so incredibly alike.
As such, if we call up an existing record to edit I do this:
$data['fields'] = $this->customer_model->get_customer($id);
If the form is submitted to save the record, or if we're adding a record for the first time, the form has the potential to reload if the user makes a mistake so I populate $data['fields'] this way instead:
$data['fields'] = array(
'company' => $this->input->post('company') ?: '',
'website' => $this->input->post('website') ?: '',
'credit_limit' => $this->input->post('credit_limit') ?: ''
);
My form element looks like this:
<input type="text" name="company" value="<?php echo set_value('company', $fields['company']); ?>" />
But I'm thinking it may as well look like this:
<input type="text" name="company" value="<?php echo escape_html($fields['company']); ?>" />
Since the form data could come from either user input (when adding or saving) or from the database (when retrieving a record to edit) I cannot rely entirely on post() or set_value() without the 2nd parameter. Furthermore, the second parameter for set_value() will always exist ($fields['company'] in this example) because it's initialized from the start, which is why I am thinking of just using it directly.
Is there a problem with this approach?
If you want to populate form fields on FALSE return of Form Validation or insert data for editing operations, I suggest you to use following helper:
Usage
<input type="text" name="last_name" value="<?=vset_value('last_name','',$rs);?>">
Explanation
$rs here is the $db data for record (if you are sending it to view). To stay at the safe side please include $this->data['rs'] = false; at your controller. If $rs is set and true, helper take results from it and display it. Otherwise it displays if the key exist in $_POST. If both don't exists, it display default value.
Helper
/**
* vayes_helper::vset_value
*
* Retains state of INPUT text after Form Validation
*
* #access public
* #param string name of INPUT tag
* #param string default value for INPUT tag
* #param mixed DB Result (array or object)
* #return string
*/
if(!function_exists('vset_value')) {
function vset_value ($name_of_input,$default_state='',$db_result_array='') {
$CI = &get_instance();
$render_state = $default_state;
if($CI->input->post()) {
$render_state = $CI->input->post($name_of_input);
} else {
if(is_object($db_result_array) && isset($db_result_array->$name_of_input)) {
$render_state = (isset($db_result_array->$name_of_input)) ? $db_result_array->$name_of_input : $default_state;
} else if($db_result_array != '' && array_key_exists($name_of_input,$db_result_array)) {
$render_state = (isset($db_result_array[$name_of_input])) ? $db_result_array[$name_of_input] : $default_state;
}
}
return $render_state;
}
}
If you like the way, let me know. I can supply for more form input type like select, checkbox, etc.
The approach is correct, as mentioned in the CodeIgniter docs. In fact, you don't need to include the second parameter in set_value.
set_value definition:
string set_value(string $field = '', string $default = '')
//$field: If there is a submitted field with this name, its value is returned.
//$default: If there is no matching submitted field, this value is returned.
Yes,You should.
set_value() is used to re-populate a form has failed validation.
There is no additional filtering on it, so it faster.
But, I prefer some times to use $this->input->post() for the secure.
The Page Analytics I use gathers the form data automatically. Gravity Forms create tag without any name attribute. I am trying to figure out a way to assign form tag a name attribute.
The closest I have reached is this example:
<?php
add_filter("gform_form_tag", "form_tag", 10, 2);
function form_tag($form_tag, $form){
if ($form["id"] == 3){
$form_tag = preg_replace("|action='(.*?)'|", "action='custom_handler.php'", $form_tag);
return $form_tag;
}
}
?>
But I am not sure how to use preg_replace to create a name attribute for form in question.
I figured out a solution to suite myself. Sharing it for any other troubled soul. for me all I wanted was to add a name attribute for the forms so that my analytics picks up something understandable instead of ids like form-1234 so I browsed plugin/gravityforms/forms_display.php and edited it where it creates a new form tag. can be found between line 435 to 440. created a new variable to hold value of form title, edited it to remove spaces. and inserted it to the form tag string.
//Edited For Analytics
$cm_form_name = str_replace(" ", "-", $form['title']);
$form_string .= apply_filters("gform_form_tag_{$form_id}", apply_filters("gform_form_tag", "<form method='post' enctype='multipart/form-data' {$target} id='gform_{$form_id}' name='{$cm_form_name}' {$form_css_class} action='{$action}'>", $form), $form);
//End Editing
//Orginal String
//$form_string .= apply_filters("gform_form_tag_{$form_id}", apply_filters("gform_form_tag", "<form method='post' enctype='multipart/form-data' {$target} id='gform_{$form_id}' {$form_css_class} action='{$action}'>", $form), $form);
I wrote a plugin that also makes adding a name attribute (or modifying/adding/removing any other attribute for the form tag) a breeze.
http://gravitywiz.com/gravity-forms-tag-editor/
Here's an example for adding the name attribute:
new GW_Tag_Editor( array(
'tag' => 'form',
'name' => 'form_{formId}',
) );
I had a slightly different goal, but thanks to Jeff's idea I came up with the following approach that I think is worth sharing.
It appends a sanitized form name data attribute to the form tag, without touching any other attributes.
function add_form_name_data_attr($form_tag, $form){
$form_tag = str_replace('>', ' data-form-name="' . sanitize_title($form['title']) . '">', $form_tag);
return $form_tag;
}
add_filter('gform_form_tag', 'add_form_name_data_attr', 10, 2);
I can then use that data attribute in JavaScript to differentiate the various forms when calling a certain analytics API.
I have a problem with zend form, where i need to built a form where field name are same but with different belongings. Here is the input fields that i wanted inside my form.
Currently i am getting with straight html but because of this i am missing validation.
<input type="text" name="travel_guide_tab[4][title]">
<input type="text" name="travel_guide_tab[4][description]">
<input type="text" name="travel_guide_tab[6][title]">
<input type="text" name="travel_guide_tab[6][description]">
In Zend Form the element names must be unique (in some way) or else they will overwrite. However you can continue using your html form and simply filter and validate in the controller using Zend_Filter_Input. The filter and validation classes are the same ones used by Zend_Form you just pass the data in a different way.
Simple example, partial:
public function someAction() {
//set filters and validators for Zend_Filter_Input
$filters = array(
'nameOfInput' => array('HtmlEntities', 'StripTags')
);
$validators = array(
'nameOfInput' => array('NotEmpty', 'Int')
);
//assign Input
$input = new Zend_Filter_Input($filters, $validators);//can also pass the data in constructor (optional)
$input->setData($this->getRequest()->getParams());
//check input is valid and is specifically posted as 'Delete Selected'
if ($input->isValid()) {
//do some stuff
}
Good Luck.
I am using Zend Framework I have a form that allows me to create a user. It has all of the necessary validation and it works well.
I was tasked with creating a single page that allows me to create up to 25 new users with a single submit.
example:
salutation / first name / last name / email
salutation / first name / last name / email
salutation / first name / last name / email
salutation / first name / last name / email
How can I leverage the form I created for a single user and allow for each new user to get validated separately?
Is there some way to have an array of forms or something else that will achieve the same thing?
Try something like this (untested):
class BulkUserForm extends Zend_Form
{
private $_howMany = 1;
public function __construct( $howMany, $options )
{
$this->_howMany = (int) $howMany;
parent::__construct( $options );
}
public function init()
{
for( $i = 1; $i <= $this->_howMany; $i++ )
{
$userForm = new YourOriginalUserForm();
$userForm->setElementsBelongTo( 'user' . $i ); // not sure this is actually necessary anymore, because of the second param to addSubForm
$this->addSubForm( $userForm, 'user' . $i, $i );
}
}
}
Usage:
$form = new BulkUserForm( 25 /* [, $options ] */ );
echo $form;
// validation:
$form->isValid( $this->getRequest()->getPost() ); // or something similar
Explanation:
The setElementsBelongTo() call on subforms should create notations similar to this (simplified of course):
<input type="radio" name="user1[salutation]">
<input type="text" name="user1[firstName]">
<input type="text" name="user1[lastName]">
<input type="text" name="user1[email]">
You form should be able to automatically recognize the submitted POST values when validating.
Of course you should probably also look into the laying out / decorating of the sub forms, but I'll leave that up to you as an exercise. ;-)
EDIT
Sorry, the second param to addSubForm() is mandatory (added it now, and also added the optional $order param). I believe it should also automatically set the sub form to belong to the correct namespace already. Not completely sure about that though. See what happens if you leave out the setElementsBelongTo() call on the sub form.