title: CodeIgniter 4 - Validation Custom Rule Function Quandry
body: <p>In my CI4 learning, I have started by trying to simulate user sign in functionality.  I have a Controller, two Views (not shown here, but really simply pages- one a pretty much just single form, and the other one a “blank” success HTML page), a set of custom rules in the Validation.php file, and a CustomRule.php file with the first of the methods that will implement all my custom rules (which, ultimately, I’d like to have all set in the Validation.php file).  For lack of a better idea, I’ve stuck the CustomRules.php file in the app\Config\ folder.</p>
  
  <p>Here is my problem:</p>
  
  <p>For the life of me, I can’t figure out how to get the Validation service to pass additional parameters (from the form) to my custom rules function called ‘user_validated’.  The CI4 documentation describes what the custom function needs to cater for when accepting additional parameters, but not how to trigger the Validation service to pass these additional parameters to one’s custom function… so although ‘user_validated’ is called, only ‘user_email_offered’ is ever passed as in as a string- nothing else goes in, from what I can tell.  How do I get around this?</p>
  
  <p>I have tried inserting &lt; $validation->setRuleGroup('user_signin'); > before the call to validate, but found that I could move the setting of the rule group into the call to validate, using: $validationResult = $this->validate('user_signin'), which seemed to do the same, and which doesn't seem to work without the rule-group as a parameter (?).  This still doesn't seem to be what triggers the additional data to be passed to the custom rule's method. </p>
  
  <p>Extracts from my hack are appended below.</p>
  
  <p>I’d be very grateful one of you knowledgeable folk could please point me in the right direction.</p>
  
  <hr>
  
  <p>In app\Controllers\SignupTest.php:</p>
  
  <pre><code>&lt;?php
  
      namespace App\Controllers;
  
      use CodeIgniter\Controller;
  
      class SignupTest extends BaseController
      {
  
              public function index() {   // redirection from the default to signup(), signin(), ...
  
                  return $this-&gt;signup();
  
              }
  
  
              public function signup() {
  
                  helper(['form']);
  
                  $validation = \Config\Services::validation();
  
                  if ($this-&gt;request-&gt;getPost()) {     // still TBD: any different to using $this-&gt;request-&gt;getGetPost() ?
  
                      $validationResult = $this-&gt;validate('user_signin'); // set the rules to use: 'user_signin', 'user_signup'
  
                      if (!$validationResult) {
  
                          $validationErrors = $validation-&gt;getErrors();
  
                          return view('SignupTestView', $validationErrors);   // redisplay simple html form view with list of validation errors
  
                      } else {
  
                          return view('SignupTestViewSuccess');  // display view to show success 
                      }
                  } else {
  
                      return view('SignupTestView');   // initial display, in the event of there being no POST data 
  
                  }
              }
      }
  </code></pre>
  
  <p>In \app\Config\CustomRules.php:</p>
  
  <pre><code>&lt;?php
  
      namespace Config;
  
      use App\Models\UserModel;
  
      //--------------------------------------------------------------------
      // Custom Rule Functions 
      //--------------------------------------------------------------------
  
      class CustomRules
      { 
  
  
          public function user_validated(string $str, string $fields = NULL, array $data = NULL, string &amp;$error = NULL) : bool{            
  
               $user_email_offered = $str;
               $user_password_offered = '';    // to be extracted using $fields = explode(',', $fields), but $fields is never provided in the call to this user_validated method
  
  
              if (($user_email_offered !== NULL) &amp;&amp; ($user_password_offered !== NULL)) {
  
                  $usermodel = new UserModel();   // intended to create a UserEntity to permit connectivity to the database 
  
                  $user_found = $usermodel-&gt;find($user_email_offered);    // we're going to assume that user_email is unique (which is a rule configured in the database table)
  
                  if ($user_found === NULL) { // check if user exists before doing the more involved checks in the else-if section below, which may throw exceptions if there's nothing to compare (?)
  
                  ...   
  
            }
  
  }
  </code></pre>
  
  <p>In \app\Config\Validation.php:</p>
  
  <pre><code>?php 
      namespace Config;
  
      class Validation
      {
          //--------------------------------------------------------------------
          // Setup
          //--------------------------------------------------------------------
  
          /**
           * Stores the classes that contain the
           * rules that are available.
           *
           * @var array
           */
          public $ruleSets = [
              \CodeIgniter\Validation\Rules::class,
              \CodeIgniter\Validation\FormatRules::class,
              \CodeIgniter\Validation\FileRules::class,
              \CodeIgniter\Validation\CreditCardRules::class,
              \Config\CustomRules::class,
          ];
  
          /**
           * Specifies the views that are used to display the
           * errors.
           *
           * @var array
           */
          public $templates = [
              'list'   =&gt; 'CodeIgniter\Validation\Views\list',
              'single' =&gt; 'CodeIgniter\Validation\Views\single',
          ];
  
          //--------------------------------------------------------------------
          // Custom Rules
          //--------------------------------------------------------------------
  
          /* configurable limits for validation rules array below*/
          const user_email_min_lenth = 9;  
          const user_email_max_lenth = 50; 
          const user_password_min_lenth = 6;   
          const user_password_max_lenth = 25;  
  
  
          public $user_signin = [
              'user_email' =&gt; [
                  'label' =&gt; 'e-mail address',
                  'rules' =&gt; 'trim|required|valid_email|user_validated',  // user_validated is custom rule, that will have a custom error message
                  'errors' =&gt; [
                      'required' =&gt; 'You must provide an {field}',
                      'valid_email' =&gt; 'Please enter a valid {field}',
                  ]
              ],
              'user_password' =&gt; [
                  'label' =&gt; 'password',
                  'rules' =&gt; 'trim|required',
                  'errors' =&gt; [
                      'required' =&gt; 'Enter a {field} to sign in',
                      'user_password_check' =&gt; 'No such user/{field} combination found',
                  ] 
  </code></pre>