Welcome Guest, Not a member yet? Register   Sign In
[solved:] Catching validation errors after redirect
#1

(This post was last modified: 04-10-2020, 05:04 AM by dgvirtual.)

I am trying to create a workable form with validation based on the CI4 user guide's tutorial "Create a form".  Instead of loading views on validation errors I am trying to use a redirect in the controller:

PHP Code:
return redirect()->back()->withInput(); 

I have found that the code loads the form fields with previously entered data if I use form helper to build the form in the view with set_value() function, like this:

PHP Code:
<?php echo form_textarea('body',set_value('body'));?>

However, I cannot find a way to retrieve the validation error messages in the form.

If I dump the session data in the controller

PHP Code:
var_dump($_SESSION); 
I can see the validation errors in output like this

Code:
...
  ["_ci_validation_errors"]=>
  string(52) "a:1:{s:4:"body";s:27:"The body field is required.";}"
}
so it seems I do not need to use setFlashdata function, but I cannot find a function to retrieve that _ci_validation_errors array ...

Could anyone help me please?
==

Donatas G.
Reply
#2

(This post was last modified: 04-07-2020, 03:47 PM by seunex.)

I usually store my error message in array and pass it to session.

PHP Code:
$errors = array(
'error' => $validation->listErrors()
); 

Then I pass it to session like

PHP Code:
session()->setFlashdata($errors);

return 
redirect()->back() 


I display them in my view like

PHP Code:
if session()->has('error')
{
echo 
$session+)->error;



That my style
Reply
#3

(04-07-2020, 03:45 PM)seunex Wrote: I usually store my error message in array and pass it to session.

Thank you, I think i will have to do the same. the variables that are transmitted over session by default seem to be raw, anyway. Still curious though how to access them "the CI4 way".
==

Donatas G.
Reply
#4

(This post was last modified: 04-10-2020, 05:02 AM by dgvirtual.)

So, I have found a way to retrieve validation errors transmitted over the session via the


PHP Code:
return redirect()->back()->withInput(); 
It was actually very simple. First, noted the variable name available in the session array - _ci_validation_errors - and used it to search the code of Codeigniter. It happens - surprise! - that it is used in Validation class (system/Validation/Validation.php), in a function, - surprise again, - getErrors(): 



PHP Code:
public function getErrors(): array
{
    
// If we already have errors, we'll use those.
    // If we don't, check the session to see if any were
    // passed along from a redirect_with_input request.
    
if (empty($this->errors) && ! is_cli())
    {
        if (isset(
$_SESSION$_SESSION['_ci_validation_errors']))
        {
            
$this->errors unserialize($_SESSION['_ci_validation_errors']);
        }
    }

    return 
$this->errors ?? [];


So, this function searches for validation errors returned by the validation procedure, and if such are not found (and they are not found if the form is not echoed but reloaded) it searches for errors array in the session and unserializes it. Another reference to the  _ci_validation_errors is in Redirectresponse class ( system/HTTP/RedirectResponse.php ), where function withInput() serializes the validation errors and adds them to session variable _ci_validation_errors using setFlashdata() function. Another function in Validation class, the listErrors() function, takes the array returned by getErrors() function and produces an html list of errors.

With this knowledge I went back to my controller's create() function and tried simply retrieving the errors using function listErrors() of the validation class:


PHP Code:
    public function create()
    {
        
helper(['form','text']);
        
$session session(); 
        
$model = new NewsModel();
        
$validation = \Config\Services::validation();
        
$validation->setRules([
            
'title' => 'required|min_length[3]|max_length[255]',
            
'body'  => 'required'
            
]);
        if (! 
$validation->withRequest($this->request)->run())
        {
            if(
is_null($this->request->getVar('submit'))) 
            {
    
/* THE CODE TO RETRIEVE THE VALIDATION ERRORS */
                
$errors $validation->listErrors();
    
/* END THE CODE TO RETRIEVE THE VALIDATION ERRORS */
                
echo view('templates/header', ['title' => 'Create news','errors' => $errors]);
                echo 
view('news/create');
                echo 
view('templates/footer');
            }
            else
            {
                return 
redirect()->back()->withInput();
            }
        }
        else
        {
            
$model->save([
                
'title' => $this->request->getVar('title'),
                
'slug'  => convert_accented_characters(url_title($this->request->getVar('title'), '-'TRUE)),
                
'body'  => $this->request->getVar('body'),
            ]);
            echo 
view('news/success');
        }
    } 


Then I tried to run the code with an empty message body, so that validation would fail, I got an unexpected result: I got error messages indicating both field validations failed! This problem was, actually, what prompted me to start this thread in the first place. But now I knew this was not an inteded behaviour of the framework.

Then I looked back into the code of getErrors() function of the Validation class and saw what the problem was: I checked if validation has been run and THEN retrieved the error messages, which resulted in the getErrors() class catching the current errors, not the errors transmitted over the session variable. Then I moved the line


PHP Code:
$errors $validation->listErrors(); 
to execute before the


PHP Code:
if(is_null($this->request->getVar('submit'))) 
and the code started working as expected.
==

Donatas G.
Reply
#5

or you can use different way

$valid = \Config\Services::validation();
redirect()->back()->withInput()->with('validation', $valid);
Reply




Theme © iAndrew 2016 - Forum software by © MyBB