set_value() not working without having a validation rule - php

I have found that when I use set_value() in a Codeigniter 2 form, to repopulate a form field, it only returns a value if I have a validation rule set for this input.
Which is fine if I am validating a field, but not fine if it is an optional input with no validation.
So what I plan to do now as standard for every single form I process, is add this little hack to create 'empty' rules before adding any genuine validation rules;
//iterate over every posted value and create an empty rule for it.
foreach ($this->input->post() as $key => $value) {
$this->form_validation->set_rules($key);
}
Then if I have any 'real' rules I will add them afterwards so they overwrite the previous empty rule.
What I want to know is, is there another way to do this, built into the framework? It seems like a bit of an omission that these values are not available to the set_value() function until they have a rule, which makes me wonder if I have missed a configuration option?

Instead of set_value, you can use $this->input->post() to get its submitted value.
For ex:
<input name='test_name' type='text' value = '<?php echo $this->input->post("test_name");?>' />

If you're using the validation library, you have to set at least a
validation rule for your field to get set_value() form helper
function to work.
If you're interested to know the reason behind this and/or how set_*() functions work, you can refer to my answer here:
set_select() helper function is not working
In this particular instance, I suggest using $_POST[$key] to fetch the posted value of the field. Because Input::post() method doesn't do anything more than reading the value from $_POST.
Thus, you could get the value as follows:
$value = isset($_POST[$field]) ? $_POST[$field] : 'default value';
// Or echo off the errors
$value = #$_POST[$field]) ?: 'default value'; // PHP 5.3+ syntax
(Check the result).
You could also extend the CI form helper in order to to add a new helper function:
application\helpers\MY_form_helper.php
if (! function_exists('get_value')) {
function get_value($field = '', $default = '')
{
if (! isset($_POST[$field]))
{
if (count($_POST) === 0 AND $default !== '')
{
return $default;
}
return '';
}
return $_POST[$field];
}
}
Then could use the helper function as follows:
<input name="my_field" type="text" value="<?php echo get_value('my_field', 'Default Value'); ?>">

Related

Laravel - both input values can't be no how to validate?

I'm using Laravel for a project and want to know how to validate a particular scenario I'm facing. I would like to do this with the native features of Laravel if this is possible?
I have a form which has two questions (as dropdowns), for which both the answer can either be yes or no, however it should throw a validation error if both of the dropdowns equal to no, but they can both be yes.
I've check the laravel documentation, but was unsure what rule to apply here, if there is one at all that can be used? Would I need to write my own rule in this case?
very simple:
let's say both the fields names are foo and bar respectively.
then:
// Validate for those fields like $rules = ['foo'=>'required', 'bar'=>'required'] etc
// if validation passes, add this (i.e. inside if($validator->passes()))
if($_POST['foo'] == 'no' && $_POST['bar'] == 'no')
{
$messages = new Illuminate\Support\MessageBag;
$messages->add('customError', 'both fields can not be no');
return Redirect::route('route.name')->withErrors($validator);
}
the error messge will appear while retrieving.
if you get confuse, just dump the $error var and check how to retrieve it. even if validation passes but it gets failed in the above code, it won't be any difference than what would have happened if indeed validation failed.
Obviously don't know what your form fields are called, but this should work.
This is using the sometimes() method to add a conditional query, where the field value should not be no if the corresponding field equals no.
$data = array(
'field1' => 'no',
'field2' => 'no'
);
$validator = Validator::make($data, array());
$validator->sometimes('field1', 'not_in:no', function($input) {
return $input->field2 == 'no';
});
$validator->sometimes('field2', 'not_in:no', function($input) {
return $input->field1 == 'no';
});
if ($validator->fails()) {
// will fail in this instance
// changing one of the values in the $data array to yes (or anything else, obvs) will result in a pass
}
Just to note, this will only work in Laravel 4.2+

JForm - Multiple Validation Rules?

I have a form (defined in XML) which is used with Joomla's JForm to handle. What I'd like to know is if it's possible to validate against multiple rules at once.
Typically, I've come to understand that Joomla's JForm accepts only one rule for validation, defined in the XML of the form:
Joomla's JForm internals also seem to suggest I can't, the following area being the only one I can find handing validation:
// Get the field validation rule.
if ($type = (string) $element['validate'])
{
// Load the JFormRule object for the field.
$rule = $this->loadRuleType($type);
// If the object could not be loaded return an error message.
if ($rule === false)
{
throw new UnexpectedValueException(sprintf('%s::validateField() rule `%s` missing.', get_class($this), $type));
}
// Run the field validation rule test.
$valid = $rule->test($element, $value, $group, $input, $this);
// Check for an error in the validation test.
if ($valid instanceof Exception)
{
return $valid;
}
}
This isn't wrapped in a loop, so I'm quite concerned that I can't apply multiple rules at once to a particular field.
Are you looking for server or client side validation? Sean's answer seems to cover server side so I figured I'd add some insight into client side techniques.
You enable client side validation two ways. The first and simplest would be by adding the following to your form field definition, which would ensure any required fields are filled out to proceed.
required="true"
Second would be to add a class to the form field definition to let Joomla core know you want to validate the field and how. Joomla offers 4 validations built into the core: validate-username, validate-password, validate-numeric and validate-email.
These in and of themselves don't help you much, but the ability to create and reference custom client-side validations does. For my example we're going to ensure a check box is marked before allowing the form to submit. So in the form field definition I'll add:
class="validate-checked"
On the page where you render the form, be sure to load the JS library for validation using:
JHtml::_('behavior.formvalidation');
In addition, add the class form-validate to your form HTML element.
Add this javascript to handle the actual validation, here I have a checkbox input type with an ID of tos I'm verifying. In the setHandler method, the first parameter is the custom name I entered in the form field definition class statement, validate-checked:
<script>
window.addEvent('domready', function(){
document.formvalidator.setHandler('checked', function(value) {
var tos = document.getElementById('tos');
if (tos.checked) {
return true;
} else {
return false;
}
});
});
</script>
Now, capture the submit event and verify all core and custom validations passed before submitting the form.
Joomla.submitbutton = function(task) {
if (task == 'user.cancel' || document.formvalidator.isValid(document.id(".myFormId"))) {
Joomla.submitform(task, document.getElementById('myformId'));
}
You can create as many custom client-side validation scripts as you want. Inside the setHandler method you can interact with the DOM and use the passed in value parameter to determine if the field should pass, only needing to worry about returning true or false to indicate results and Joomla will handle the rest. So you can either create one complicated validation or many smaller concise validations to suit your needs.
Hope that helps...
This is a common request. There are a few possibilities. You could write your own JFormRule with more complex validation. The other is that you could programatically add an attribute to the field that runs the additional validation sort of like what Sean is advocating.
This answer assumes that it is not possible to natively add multiple rules on one field.
Assuming that it is not possible to apply multiple rules to one field natively, then it may be possible to extend JForm::validateField() to enable such a feature by simply calling the validate method for each validation rule found.
// Extending class JForm
protected function validateField(SimpleXMLElement $element, $group = null, $value = null, JRegistry $input = null) {
if($type = (string) $element['validate'])
{
$multiple_types = explode('|', $type);
if(is_array($multiple_types) && $multiple_types[0] !== $type)
{
foreach($multiple_types as $single_type)
{
$result = parent::validateField($element, $group, $value, $input);
// Validation failed, return the result and stop validating.
if($result !== true)
{
return $result;
}
}
return true;
}
else
{
return parent::validateField($element, $group, $value, $input);
}
}
}
With that example, validation rules could be structured like:
validate="rule1|rule2"

Should I use set_value() to repopulate a form in CodeIgniter

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.

Laravel foreach input all update fails because of form token

I recently found my problem what is causing my form error.
I create a form post and loop throuh them
public function update()
{
$input = Input::all();
foreach ($input as $key => $value) {
$update = Setting::find($key);
$update->value = $value;
$update->save();
}
return Redirect::back();
}
The problem is i get the following error
Creating default object from empty value
Because the token is included in the form post what Laravel automaticly renders to a form
if i stop using Laravel form open and use the html form tag it all works fine.
Is there any way to bypass this with laravel form open or should i use the html form tag?
change
$input = Input::all();
to
$input = Input::except('_token');
Make sure your $update = Setting::find($key); returns a valid object, because, that error should be triggered when $update is NULL or not defined and you are trying to use this in your code
$update->value = $value;
This warning Creating default object from empty value occurs when E_STRICT is on in the system, but this is not the real problem, instead, you are not getting the desired result, most probably Setting::find($key) is not getting the thing you asked for and creating a new Setting object instead, check your model and make sure you are passing the right value in ::find($key), key should be primary key.
Update :
Also remember, when your using
$input = Input::all();
foreach ($input as $key => $value) { ... }
In this case, $key will be the name of your input/field used in the form and it may contain hidden _token field but _token is probably not available in the database as a field/column. So, you may try to get everything except _token
$input = Input::except('_token'); // get everything without _token
to get everything without _token field (but not sure if this solves the problem or not).

Zend_Form set and validate field value manually

I have a Zend_Form with a dropdown field.
When the user sets a value in the url this one should be selected as default value in this dropdown.
So what i do at the moment is this:
$parlang = $this->getRequest()->getParam('lang');
if($parlang){
$this->view->filterForm->getElement('ddLanguage')->setValue($parlang);
}
if ($this->getRequest()->isPost()) {
if($this->view->filterForm->isValid($_POST)){
...
...
...
No i want to check if the value of the variable is even a valid value for the dropdown? How can i check this in coorporation with the form validation. Yes i can check the variable against a array or so but this seems to be "fighting against the framework".
So what is the Zend way to do such a thing?
Edit:
My final solution for all who are interested, is:
$parlang = $this->getRequest()->getParam('lang');
if($parlang){
$ddLanguage = $this->view->filterForm->ddLanguage;
if($ddLanguage->isValid($parlang)){
$ddLanguage->setValue($parlang);
$language = $parlang;
}
}
I ran a quick test and it looks like one method you can use is Zend_Form_Element_Select::getMultiOption() to check if the language exists in the select values.
<?php
$parlang = $this->getRequest()->getParam('lang');
if ($parlang) {
$el = $this->view->filterForm->getElement('ddLanguage');
// attempt to get the option
// Returns null if no such option exists, otherwise returns a
// string with the display value for the option
if ($el->getMultiOption($parlang) !== null) {
$el->setValue($parlang);
}
}
If your Multiselect element contains a list of country, I would just populate a default in your element value according to the one in the URL.
In order to do so, you could create a custom Zend_Form_Element as follow:
class My_Form_Element_SelectCountry extends Zend_Form_Element_Select
{
protected $_translatorDisabled = true;
public function init()
{
$locale = Zend_Registry::get('Zend_Locale');
if (!$locale) {
throw new Exception('No locale set in registry');
}
$countries = Zend_Locale::getTranslationList('territory', $locale, 2);
unset($countries['ZZ']);
// fetch lang parameter and set US if there is no param
$request = Zend_Controller_Front::getInstance()->getRequest();
$lang = $request->getParam('lang', 'US');
// sort your country list
$oldLocale = setlocale(LC_COLLATE, '0');
setlocale(LC_COLLATE, 'en_US');
asort($countries, SORT_LOCALE_STRING);
setlocale(LC_COLLATE, $oldLocale);
// check weither the lang parameter is valid or not and add it to the list
if (isset($countries[$lang])) {
$paramLang = array($lang => $countries[$lang]);
$countries = array_merge($paramLang, $countries);
}
$this->setMultiOptions($countries);
}
}
You get the idea from this custom form.
If what you're trying to do isn't a Multiselect field filled by a country list but a list of language instead, then the logic is the same, you just need to change the call to the static method Zend_Locale::getTranslationList()and grab whatever information you need.
One more thing, if you just want a single element in your Multiselect element, then go for a Zend_Form_Element_Hidden.
It's a lot of "if" but I can't understand how looks like your Multiselect element exactly from your question.
Now let's take a look on the validation side, when you're using a Multiselect element, Zend_Framework automatically adds an InArray validator, which means that you don't have anything to do to check weither the data sent are correct or not. isValid is going to do it for you.
Weither a user let the default parameter and everything will be fine, or he modifies/deletes this parameter and the default parameter (en_US in this case, see code above) is going to be set as a default value for the Multiselect field.
To answer your last question, no it's not against the framework to check a variable set by a user and compare it with an array (from getTranslationList()for example). I would say it's even the recommended way to do things.

Categories