title: CodeIgniter 4: Call to member function on null where post request is valid in var_dump()
body: <p>** Very new to CodeIgniter so please be kind! **</p>
  <p>I have an issue with my two user authentication forms: <code>users/register.php</code> and <code>users/login.php</code> where I cannot pass the post input to functions in my model.</p>
  <p>As of now, I'm getting the error <code>Call to member function addUser() on null</code> on the registration form and a validation error on the login form that states the username/password don't match any credentials in the database. Both seem to stem from post being null although it is not.</p>
  <p>I have done a var_dump on <code>$login</code> which is defined as <code>$login = $this-&gt;request-&gt;getPost()</code> as well as inspected the request in Firefox Developers Browser to find all the post data correctly displayed. I am stumped. Why can't I pass this array to my model?</p>
  <p>Here is a screenshot of the post request for <code>login.php</code> (the same can be said for <code>registration.php</code> and is not included).</p>
  <p><a href="https://i.stack.imgur.com/WHJrH.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/WHJrH.png" alt="Screenshot showing inspector mode in Firefox Developer Browser." /></a></p>
  <p>These are my routes:</p>
  <pre class="lang-php prettyprint-override"><code>// Login and Registration
  $routes-&gt;match(['get', 'post'], 'users/register', 'Users::register');
  $routes-&gt;match(['get', 'post'], 'users/login', 'Users::login', [&quot;filter&quot; =&gt; &quot;noauth&quot;]);
  </code></pre>
  <p>Here is my model UserModel.php in its entirety:</p>
  <pre class="lang-php prettyprint-override"><code>class UserModel extends Model
  {
      protected $DBGroup          = 'default';
      protected $table            = 'users';
      protected $primaryKey       = 'username';
      protected $useAutoIncrement = false;
      protected $insertID         = 0;
      protected $returnType       = 'object';
      protected $useSoftDelete    = false;
      protected $allowedFields    = [
          'username',
          'password',
          'id',
          'role',
          'profile_image',
          'profile_views',
          'last_login',
          'about_me',
          'age',
          'gender',
          'occupation',
          'hometown',
          'country',
          'fav_shape',
          'fav_color',
          'created',
          'modified',
      ];
  
      // Dates
      protected $useTimestamps    = true;
      protected $dateFormat       = 'datetime';
      protected $createdField     = 'created';
      protected $modifiedField    = 'modified';
  
      // Callbacks
      protected $allowCallbacks   = true;
      protected $beforeInsert     = ['beforeInsert'];
  
      public function __construct() 
      {
          parent::__construct(); 
      }
  
      protected function beforeInsert(array $data)
      {
          $data = $this-&gt;passwordHash($data);
  
          return $data;
      }
  
      protected function passwordHash(array $data)
      {
          if (isset($data['password'])) {
  
              $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
          }
  
          return $data;
      }
  
         public function lastLogin($username)
      {
          $this-&gt;builder()
              -&gt;where('username', $username)
              -&gt;update('last_login', date('Y-m-d H:i:s'));
      }
  
      public function addUser($newUser)
      {
          $builder = $this-&gt;builder()
              -&gt;set($newUser)
              -&gt;insert();
  
          if ($builder-&gt;affected_rows() == 1) {
  
              return TRUE;
          
          } else {
  
              return FALSE;
          }
      }
  
      public function getUser($username)
      {
          $builder = $this-&gt;builder()
              -&gt;where(['username' =&gt; $username])
              -&gt;limit(1);
  
          if ($builder-&gt;countAllResults() === 1) {
              
              return $builder-&gt;get()-&gt;getRow();
          
          } else {
  
              return FALSE;
          }
      }
  }
  </code></pre>
  <p>Here are excerpts from my controller <code>Users.php</code>:</p>
  <pre class="lang-php prettyprint-override"><code>class Users extends BaseController
  {
      protected $userModel;
  
      public function __construct() 
      {
          $userModel = new UserModel();
      }
  
      public function login()
      {
          $validation = \Config\Services::validation();
  
          // Set session variable
          $session = session();
  
          if ($this-&gt;request-&gt;getMethod() === 'post' &amp;&amp; ! empty($_POST)) {   
              $validation-&gt;getRuleGroup('login');
              $validation-&gt;setRuleGroup('login');
              $validation-&gt;withRequest($this-&gt;request)-&gt;run(); 
  
              $recaptchaResponse = trim($this-&gt;request-&gt;getVar('g-recaptcha-response'));
  
              $userIp = $this-&gt;request-&gt;getIPAddress();
  
              $secret = env('recaptcha2_secretkey');
  
              $credential = [
                  'secret'    =&gt; $secret,
                  'response'  =&gt; $recaptchaResponse,
                  'remoteip'  =&gt; $userIp,
              ];
  
              $verify = curl_init();
  
              curl_setopt($verify, CURLOPT_URL, 'https://www.google.com/recaptcha/api/siteverify');
              curl_setopt($verify, CURLOPT_POST, TRUE);
              curl_setopt($verify, CURLOPT_POSTFIELDS, http_build_query($credential));
              curl_setopt($verify, CURLOPT_SSL_VERIFYPEER, FALSE);
              curl_setopt($verify, CURLOPT_RETURNTRANSFER, TRUE);
  
              $response = curl_exec($verify);
  
              $status = json_decode($response, TRUE);
  
              curl_close($verify);
  
              if (empty($validation-&gt;getErrors()) &amp;&amp; $status['success']) {
                  $login = $this-&gt;request-&gt;getPost();
  
                  $user = $this-&gt;userModel-&gt;getUser($login['username']);
  
                  // Storing session values
                  $this-&gt;setUserSession($user);
  
                  // Storing success message
                  $session-&gt;setFlashdata('success', 'You have successfully logged in!');
  
                  // Update last login datetime
                  $this-&gt;userModel-&gt;lastLogin($login['username']);
  
                  // Redirecting to dashboard after login
                  if ($user['role'] == 1) {
  
                      return redirect()-&gt;to('admin/dashboard');
                  
                  } elseif ($user['role'] == 0) {
  
                      return redirect()-&gt;to('members/dashboard');
                  }
              } else {
  
                  $data = [
                      'title'     =&gt; 'Login',
                      'errors'    =&gt; $validation-&gt;getErrors(),
                  ];
  
                  echo view('templates/index_header', $data);
                  echo view('users/login');
                  echo view('templates/footer', $data);
              }   
          } else {
              $data = [
                  'title' =&gt; 'Login',
              ];
  
                  echo view('templates/index_header', $data);
                  echo view('users/login');
                  echo view('templates/footer', $data);  
          }
      }
  
      /**
       * Sets session with user id, username, isLoggedIn, and role for use in member/admin site
       * @param model user data
       * @return boole if session was set successfully
       */
      private function setUserSession($user)
      {
          $data = [
              'id' =&gt; $user-&gt;id,
              'username' =&gt; $user-&gt;username,
              'profile_image' =&gt; $user-&gt;profile_image,
              'isLoggedIn' =&gt; true,
              'role' =&gt; $user-&gt;role,
          ];
  
          if (session()-&gt;set($data)) {
              
              return true;
          
          } else {
  
              return false;
          }
      }
  
      public function register() 
      {
          $validation = \Config\Services::validation();
  
          if ($this-&gt;request-&gt;getMethod() == 'post' &amp;&amp; ! empty($_POST)) {
  
              $validation-&gt;getRuleGroup('registration');
              $validation-&gt;setRuleGroup('registration');
              $validation-&gt;withRequest($this-&gt;request)-&gt;run(); 
  
              if (empty($validation-&gt;getErrors())) {
  
                  $newUser = $this-&gt;request-&gt;getPost();
  
                  if ($this-&gt;userModel-&gt;addUser($newUser)) {
  
                      $this-&gt;session-&gt;setFlashdata('success', 'Successful Registration');
  
                      $data['title'] = 'Login';
  
                      echo view('templates/index_header', $data);
                      echo view('users/login');
                      echo view('templates/footer', $data);
  
                  } else {
  
                      $this-&gt;session-&gt;setFlashdata('error', 'Something went wrong with your registration! Please try again.');
                  }
  
              } else {
  
                  $data = [];
  
                  $data = [
                      'title'     =&gt; 'Register',
                      'script'    =&gt; 'js/click_link',
                      'errors'    =&gt; $validation-&gt;getErrors(),
                  ];
                  
                  echo view('templates/index_header', $data);
                  echo view('users/register', $data);
                  echo view('templates/footer', $data);
              }
          } else {
              $data = [
                  'title'         =&gt; 'Register',
                  'script'        =&gt; 'js/click_link',
              ];
          
              echo view('templates/index_header', $data);
              echo view('users/register', $data);
              echo view('templates/footer', $data);
          }
      }
  }
  </code></pre>
  <p>These are my validation rules in <code>Config\Validation</code>:</p>
  <pre class="lang-php prettyprint-override"><code>/**
       *  Registration
       */
      public $registration = [
          'username'      =&gt; 'required|is_unique[users.username,username]|min_length[5]|max_length[25]|alpha_dash|badWordsFilter[username]',
          'password'      =&gt; 'required|min_length[8]|max_length[255]|regex_match[/^(?=.*[!@#$%^&amp;*-])(?=.*[0-9])(?=.*[A-Z]).{8,255}$/]',
          'pass_confirm'  =&gt; 'required|matches[password]',
          'about_me'      =&gt; 'permit_empty|max_length[250]|alpha_numeric_punct|badWordsFilter[about_me]',
          'occupation'    =&gt; 'permit_empty|max_length[50]|alpha_space|badWordsFilter[occupation]',
          'hometown'      =&gt; 'permit_empty|max_length[50]|alpha_space|badWordsFilter[hometown]',
          'age'           =&gt; 'permit_empty|less_than[100]|greater_than[0]|numeric',
          'country'       =&gt; 'permit_empty',
      ];
  /**
       *  Password Verification
       */
      public $login = [
          'password'      =&gt; 'required|validateUser[username,password]',
      ];
  </code></pre>
  <p>This is my custom rule to authenticate username and password credentials <code>User_rules</code>:</p>
  <pre class="lang-php prettyprint-override"><code>class User_rules 
  {
      /**
       * Checks if input username exists in database and then checks whether the input password matches the hash for that username
       * @param string $str is the input password
       * @param string $fields are the associated form fields that are being used
       * @param array $data is an array containing the values for the fields indexed by field names
       * @return boolean true or false depending on if the user exists and the password matches the hashed password stored in the database
       */
      public function validateUser(string $str, string $fields, array $data)
      {
          $userModel = new UserModel();
  
          $user = $userModel-&gt;getUser($data['username']);
  
          if(!$user) {
  
              return FALSE;
          }
  
          return password_verify($data['password'], $user-&gt;password);
      }
  </code></pre>
  <p>Lastly, my view for <code>login.php</code>:</p>
  <pre class="lang-php prettyprint-override"><code>&lt;div class='form-container'&gt;
  
      &lt;?= form_open('users/login',['autocomplete' =&gt; FALSE]); ?&gt;
  
          &lt;div class='form-header'&gt;
              &lt;h2&gt;Login&lt;/h2&gt;
          &lt;/div&gt;
          
          &lt;div class='form-body'&gt;
  
              &lt;div class='form-row'&gt;
                  &lt;div class='input-container'&gt;
                      &lt;i class='fas fa-user'&gt;&lt;/i&gt;
  
                      &lt;?php $attributes = [
                          'type'      =&gt; 'text',
                          'name'      =&gt; 'username',
                          'class'     =&gt; 'input-field',
                          'id'        =&gt; 'username',
                          'placeholder'   =&gt; 'Username',
                          'required'      =&gt; TRUE,
                      ]; ?&gt;
                      &lt;?= form_input($attributes); ?&gt;
                  
                  &lt;/div&gt;
              &lt;/div&gt;
  
              &lt;div class='form-row'&gt;
                  &lt;div class='input-container'&gt;
                      &lt;i class='fas fa-lock'&gt;&lt;/i&gt;
  
                      &lt;?php $attributes = [
                          'type'          =&gt; 'password',
                          'name'          =&gt; 'password',
                          'class'         =&gt; 'input-field',
                          'placeholder'   =&gt; 'Password',
                          'required'      =&gt; TRUE,
                      ]; ?&gt;
                      &lt;?= form_input($attributes); ?&gt;
                    
                  &lt;/div`&gt;
              &lt;/div&gt;
          &lt;/div&gt;
                  
          &lt;div class='captcha-container'&gt;
              &lt;div class='g-recaptcha' data-sitekey='&lt;?= env('recaptcha2_sitekey'); ?&gt;'&gt;&lt;/div&gt;
          &lt;/div&gt;
  
          &lt;div class='form-footer'&gt;
  
              &lt;?php $submit = [
                      'name'      =&gt; 'loginSubmit',
                      'value'     =&gt; 'Login',
                      'class'     =&gt; 'submit-btn',
              ];?&gt;
              &lt;?= form_submit($submit); ?&gt;
      
          &lt;/div&gt;
  
          &lt;h4 style='text-align: center'&gt;Not a member yet? Register 
              &lt;a href= &lt;?= site_url('users/register'); ?&gt; title = 'Register'&gt; HERE&lt;/a&gt;
          &lt;/h4&gt;
  
       &lt;?= form_close(); ?&gt;
  &lt;/div&gt;
  </code></pre>