Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate form field in PHP using Object Oriented Technique

I have created a class 'validate' to validate two fields i.e 'firstname' and 'lastname'. It is not working fine, it is showing error when field is empty but when I submit the form with non-empty fields the error is still there. How to execute this on form submission?

 <?php

  class validation {

  public $firstName, $lastName, $errorFirstName = '', $errorLastName = '';

  function __constructor($fName, $lName){
    $this->firstName = $fName;
    $this->lastName = $lName;
  }

  function check(){

      if($_SERVER["REQUEST_METHOD"] == "POST"){
        if(empty($this->firstName)){
        $this->errorFirstName = 'First name is required';
       } else {
        $this->errorFirstName = 'Input is okay';
       }

     if(empty($this->lastName)){
         $this->errorLastName = 'Last name is required';
      }  else {
       $this->errorLastName = 'Input is okay';
      }
    }
   }
  }

 $obj = new validation($_POST['firstname'], $_POST['lastname']);
 $obj->check();
 $errorF = $obj->errorFirstName;
 $errorL = $obj->errorLastName;

 ?>

  <!DOCTYPE html>
  <html lang = "en-US" dir = "ltr">
   <head>
    <title>Home</title>
    <meta charset = "UTF-8"/>
   </head>
   <body>
   <form method = "POST" action="<?php echo $_SERVER["PHP_SELF"]?>">
    <label>First Name: </label>
    <input type = "text" name = "firstname" placeholder = "John"/>
    <p class = "error"><?php echo $errorF;?></p>
    <label>Last Name: </label>
    <input type = "text" name = "lastname" placeholder = "Doe"/>
    <p class = "error"><?php echo $errorL;?></p>
    <input type="submit">
   </form>
  </body>
 </html>
like image 249
Amir Saleem Avatar asked Apr 12 '17 15:04

Amir Saleem


3 Answers

Everyone always makes "database class" and "validation class". Ehh .... whaaaaay?

Don't make a validation class. It never works. The most .. emm ... sustainable options for validating user input are:

  • perform the validation in domain entities
  • use value objects

With using entities for validation, it is quite simple. In your case you would have class Profile where you have method setFirstName(string $name). Then within this method you do the validation and on error throw a custom made exception, like InvalidFirstName .. or something like that.

Using value objects is a bit trickier, but it prevents the code duplication. For example, you need to validate email address. So, the way you would want to use it would look something like:

try {
    $profile = new Profile;
    $profile->setEmail(new EmailAddress($_POST['email']));
} catch (InvalidArgumentException $e){
    // validation failed
}

Therefore, to get this behavior, you would have the class defined kinda like this:

class EmailAddress
{
    private $email;


    public function __construct(int $emailId = null, string $email = null)
    {
        if (!$this->isValid($email)) {
            throw new InvalidArgumentException('Not valid email address');
        }
        $this->email = $email;
    }


    private function isValid($email)
    {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }


    public function __toString()
    {
        return $this->email;
    }
}

This approach is a lot more expressive, but it tends to become a big gnarly, when interacting with persistence layer.

In practice, the best option is to use combination of these both solutions:

  • keep the validation in entities, for rules, that are unique
  • use value objects for often repeating constraints
like image 159
tereško Avatar answered Sep 30 '22 01:09

tereško


Do make a validator class.

Forms usually consist of multiple fields meaning that in suggested approach where you try/catch error while setting up the object will fail on a single field, when you might be having multiple invalid fields and on form submit you want that all fields are validated and all errors returned so they can be presented at the same time.

<?php

class MyValidator
{
    /**
     * Is form valid;
     *
     * @var bool
     */
    private $isValid = true;
    /**
     * List of errors, assoc array with error messages one per fieldName
     *
     * @var array
     */
    private $errors = [];

    /**
     * Check if form is valid
     *
     * @return bool
     */
    public function isValid(): bool
    {
        return $this->isValid;
    }

    /**
     * Get error message
     *
     * @param $fieldName
     * @return mixed|string
     */
    public function getError($fieldName)
    {
        return isset($this->errors[$fieldName]) ? $this->errors['fieldName'] : '';
    }

    /**
     * @param array $rules list of rules
     * @param array $payload list of form parameters
     * @return bool Return validation result, same as isValid
     */
    public function validate(array $rules, array $payload)
    {
        foreach ($rules as $rule) {
            if (!$this->validateRequired($rule, $payload)) {
                continue;
            }
            switch ($rule['type']) {
                case 'string':
                    $this->validateString($rule, $payload);
                    break;
                case 'email':
                    $this->validateEmail($rule, $payload);
                    break;
                    //extend with other validation rules as needed
            }
        }

        return $this->isValid();
    }

    public function validateRequired(array $rule, array $payload)
    {
        if (true === $rule['required'] && !isset($payload[$rule['fieldName']])) {
            $this->isValid = false;
            $this->errors[$rule['fieldName']] = 'This field is required';

            return false;
        }

        return true;
    }

    public function validateString($rule, $payload)
    {
        // Checkup logic, set $this->isValid to false if not valid, add
        // See add $this->errors[$rule['fieldname']] = 'your message';
    }

    public function validateEmail($rule, $payload)
    {
        // Checkup logic, set $this->isValid to false if not valid, add
        // See add $this->errors[$rule['fieldname']] = 'your message';
    }

}

// Call validator by giving validator ruleset in the format

$rules = [
    [
        'fieldName' => 'firstName',
        'type' => 'string',
        'minLength' => 10,
        'maxLength' => 20,
        'required' => true,
    ],
    [
        'fieldName' => 'email',
        'type' => 'email',
        'required' => true,
    ]
];

$validator = new MyValidator();
$isValid = $validator->validate($rules, $_POST);

// if false do repeat form with error messages shown
// use $validator->getError('firstName'); to get error message for a field.
like image 22
MaxT Avatar answered Sep 30 '22 02:09

MaxT


In the code mentioned, it is written in a way that the form values will be passed to the class while creating it, and inside the constructor, class variables will be initialized with the values provided.

After that check() method will check whether the fields are empty or not.

But this is not working as expected because the values passed from the form could not be initialized to $firstName and $lastName.

The reason for this is,

function __constructor() 

is not a constructor of a class, it should be

function __construct()

which is the reason why the class variables are not assigned the values given from the form and the error is showing up.

Once you modify it, the issue will be solved.

like image 29
Rajen Ranpara Avatar answered Sep 30 '22 01:09

Rajen Ranpara