Extraction of Form Validation Object and Authenticate Class
Tags: webdev, beginners, css
Published: 2024-07-09 19:33:02

In our previous project, we learned how to login or logout a registered user. But today, we will learn how to extract a form validation object and about authenticate class extraction in the project. 

## On VS Code Side 

To start the project, we need to add a new directory named Http, then move the controllers into this new directory. Next, we need to add another new directory in Http named Forms and add a new file LoginForm in this directory. Then, we need to run the project, which will show an error because the controllers have been moved to a new directory and their routes need to be updated in `routes.php`.

```php
$router->get('/', 'index.php');
$router->get('/about', 'about.php');
$router->get('/contact', 'contact.php');
$router->get('/notes', 'notes/index.php')->only('auth');
$router->get('/note', 'notes/show.php');
$router->delete('/note', 'notes/destroy.php');
$router->get('/note/edit', 'notes/edit.php');
$router->patch('/note', 'notes/update.php');
$router->get('/notes/create', 'notes/create.php');
$router->post('/notes', 'notes/store.php');
$router->get('/register', 'registration/create.php')->only('guest');
$router->post('/register', 'registration/store.php')->only('guest');
$router->get('/login', 'session/create.php')->only('guest');
$router->post('/session', 'session/store.php')->only('guest');
$router->delete('/session', 'session/destroy.php')->only('auth');
```

## Extract Form Validation Object

To extract a form validation object, we need to go to session/store.php and cut the code that checks if the provided email and password are correct. We then need to move this code to the LoginForm.php file, which is located in the Http/Forms directory.


## LoginForm

The `LoginForm.php` file will contain data related to user login to validate forms and protected errors array that points to errors in project 
```php
<? php
namespace Http\Forms;
use Core\Validator;
class LoginForm {
  protected $errors = [];
  public function validate($email, $password) {
    if (!Validator::email($email)) {
      $this->errors['email'] = 'Please provide a valid email address.';
    }
    if (!Validator::string($password)) {
      $this->errors['password'] = 'Please provide a valid password.';
    }
    return empty($this->errors);
  }
  public function errors() {
    return $this->errors;
  }
  public function error($field, $message) {
    $this->errors[$field] = $message;
  }
}
```
Now we can see that project is working well.

## Extract Authenticate Class

 Next , to extract an authenticate class, we need to select all code segments that are used to authenticate the user, such as checking the user's email and password. We then need to add a new file `authenticator.php`, which will contain an authenticate class used for user authentication then login and logout functions were imported.


```php
<?ph
namespace Core;
class Authenticator {
  public function attempt($email, $password) {
    $user = App::resolve(Database::class)
      ->query('select * from users where email = :email', [ 'email' => $email ])
      ->find();
    if ($user) {
      if (password_verify($password, $user['password'])) {
        $this->login([ 'email' => $email ]);
        return true;
      }
    }
    return false;
  }
  public function login($user) {
    $_SESSION['user'] = [ 'email' => $user['email'] ];
    session_regenerate_id(true);
  }
  public function logout() {
    $_SESSION = [];
    session_destroy();
    $params = session_get_cookie_params();
    setcookie('PHPSESSID', '', time() - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
  }
}
```

## Update session store file

Further moving , We need to go back to session/store.php and initialize the $form and in for the new user login. We then need to implement an if condition to check if the form is valid or not. If the form is not valid, we have to redirect the user to the desired path.
```php
<?php
use Core\Authenticator;
use Http\Forms\LoginForm;

$email = $_POST['email'];
$password = $_POST['password'];

$form = new LoginForm();
if ($form->validate($email, $password)) {
  if ((new Authenticator)->attempt($email, $password)) {
    redirect('/');
  }
  $form->error('email', 'No matching account found for that email address and password.');
}
return view('session/create.view.php', [ 'errors' => $form
``` 
By making these changes we can extract a authenticate class to change the look of our code means easy to understand and modify.

I hope that you have clearly understood it