Reputation:
I have a separated file located in applications/config/form_validation.php
for my validations. Two fields for creating new user must be unique, their identification card and e-mail.
'user' => array(
array(
'field' => 'email',
'label' => 'E-MAIL',
'rules' => 'required|valid_email|is_unique[usuario.email]'
),
array(
'field' => 'cpf_cnpj',
'label' => 'CPF',
'rules' => 'required|_validate_cpf|is_unique[usuario.cpf_cnpj]'
),
...
)
In the beginning, I had used the same group of validations for editing the form, but I had problems with these two fields, for they were always being accused of not being unique.
So, I've added a hidden
field in my form to store the current value of these fields and added another, also storing the value, but the one showing in the view would be the only one to be edited, and then, in the edit
method, a condition would happen before proceeding to check if the hidden
field is different to the regular field:
// HTML
<input type="email" name="novoemail" class="email <?php echo form_error('novoemail') ? 'campo_aviso' : ''; ?>" value="<?php echo $u['email']; ?>"/>
<input type="hidden" name="email" value="<?php echo $u['email']; ?>"/>
// In `edit`
if ($this->input->post('email') !== $this->input->post('novoemail')) {
$this->form_validation->set_rules('email', 'E-MAIL', 'is_unique[usuario.email]');
}
if ($this->form_validation->run('edit_user')) { ... }
If a difference was found, add the rule to make it unique. The problem now is that any difference, even if the entered e-mail does not exist, it's failing and accusing of not being unique.
I need to find a way to edit unique fields and still have the uniqueness guaranteed.
Upvotes: 0
Views: 1845
Reputation: 8964
I agree with the methodology. The idea of using hidden fields will work and is useful for determining the correct set of rules to use with form_validation->run()
.
This answer sticks with using a config file for the rules and avoids using set_rule()
directly.
You can easily manipulate the arrays in config/form_validation.php
to return the set you need and at the same time not have a bunch of repeating code.
Consider this version of config/form_validation.php
$check_email = array(
'field' => 'novo_email',
'label' => 'E-MAIL',
'rules' => 'trim|required|valid_email|is_unique[usuario.email]'
);
$check_card = array(
'field' => 'novo_cpf_cnpj',
'label' => 'CPF',
'rules' => 'trim|required|_validate_cpf|is_unique[usuario.cpf_cnpj]'
);
$config = array(
'edit_email' => array($check_email),
'edit_cpf_cnpj' => array($check_card),
'new_user' => array($check_email, $check_card)
);
The above creates three separate sets of rules and is not recreating code structures.
There are only two cases where you even need to perform field validation.
If, for a new user, you always set the value of the hidden fields to an empty string (or NULL) the "new user" status is easy to determine. In that case you need the "new_user" rules from the config file.
If the hidden fields are not empty the you need to figure out which ones are changed and select the rules for validation depending on what is found.
Here's how to implement that logic in the edit
function. Note: The novo_*
fields are the ones the user edits.
public function edit()
{
//instead of multiple calls to $this->input->post,
//capture all the inputs in one handy array
$posted = $this->input->post();
//check for new user (true when the hidden field 'email' is blank
//if 'email' is blank then 'novo_cpf_cnpj' should be too
if(empty($posted['email']))
{
$rules = 'new_user';
}
else //not a new user. What has changed?
{
//note the use of trim - in case user added spaces to an otherwise unchanged field
$changed_email = $posted['email'] !== trim($posted['novo_email']);
$changed_cpf_cnpj = $posted['cpf_cnpj'] !== trim($posted['novo_cpf_cnpj']);
if($changed_email && $changed_cpf_cnpj)
{
//both have changed, treat like a new user
$rules = 'new_user';
}
elseif($changed_email)
{
$rules = 'edit_email';
}
elseif($changed_cpf_cnpj)
{
//only possibility left - cpf_cnpj is changed
$rules = 'edit_cpf_cnpj';
}
}
if(! isset($rules) )
{
//Not a new user and nothing changed so validation is not needed.
//Behave as if successful validation occurred and redirect to successful save page
redirect('controller/save_success');
//redirect() does not return because it always calls the PHP
//function exit thereby ending script execution.
//So, there is no need for an else to if(!isset($rules))
}
if($this->form_validation->run($rules))
{
//save to database then
redirect('controller/save_success');
}
//whatever happens when validation fails
}
Upvotes: 0
Reputation: 502
I disagree with this methodology. If the is_unique rule is failing, you should figure out why instead of trying to work around it.
Regardless, you would need to run some type of concatenated callback on the validation rule, I would think. I find validation arrays unwieldy, so I don't use them. Please feel free to adapt something like:
$this->form_validation->set_rules('test', 'Test Post', 'trim|less_than[99]'.($this->input->post('test') === $this->input->post('test2' ? 'required' : '')));
There's probably a better answer, maybe some way to use the built in "matches" validation rule. I threw this at a CI project and it didn't throw any errors, but I wasn't testing it on legitimate data, either.
Upvotes: 0