Good practices for growing class

2

Complementing a question that I posted here for some time, about a system for registering users using SOLID standard concepts, one of the problem I came across was the question of the User class being very large and can be very variable, one Once a user can have several characteristics, it follows a situation "script":

  • Each attribute has its setter / getter in the User class.
  • Each attribute has its validation rule in the userValidator class.
  • Each attribute has its "definition" in an associative array of the class userCrud.

Let's say that in another situation a user might have attributes like: corDOSOlhos, corDoCabelo and etc, I would have to always be changing the classes above, what would be a good solution for this?

User class structure:

class User {

private $attributes;

function __construct() {
    $this->userValidator = new userValidator;
}

function setName ($param) {

    if($this->userValidator->validateName($param))
        $this->attributes['name'] = $param;
}

function getAttributes () {
    return $this->attributes;
}

function getAttribute ($attr) {

    if(isset($attributes[$attr]))
        return $this->attributes[$name];
    else throw new Exception("Attribute '{$attr}' does not exist");

}

}

    
asked by anonymous 01.10.2018 / 20:18

1 answer

2

Validation

To validate each attribute it is best to have a validator for each value. With this in mind, if a new attribute arises it is not necessary to modify the class.

Basically, validators will be passed to a primary validator:

class UserValidator
{

   private $validators = [];

   public function setValidator($attribute, $validator)
   {

      $this->validator[$attribute] = $validator;

   }

   public function validate(User $user)
   {

       $messages = [];

       foreach($user->getData() as $attribute => $value){

           // Verificando se um validador para o atributo existe
           if(isset($this->validators[$attribute])){
               $message = $this->validators[$attribute]->validate($value);

               // Caso contenha a mensagem de validação, ela será armazenada em um array
               if($message){
                  $messages[$attribute] = $message;
               }

           }

       }

       // Retornando as mensagens de validação para serem utilizadas
       return $messages;

   }

 }

Using the UserValidator

To use the class you will need to pass the validators to it. As you can see, to add a new validation just set the class with the setValidator method.

$userValidator = new UserValidador;
$userValidator->serValidator('name', new NameValidator);
$userValidator->setValidator('age', new AgeValidator);
$userValidator->setValidator('corDosOlhos', new CorDosOlhosValidator);
// Basta continuar configurando para cada novo atributo necessário.

The User entity

Finally, the User entity would work with an array to avoid having a huge amount of methods. If a new attribute is added, the class remains intact. Here's the implementation:

class User
{

   private $attributes;

   public function __construct(array $attributes){

       $this->attributes = $attributes;

   }

   public function getData()
   {

      return $this->attributes;

   }

   // Exemplo de método que pode ser utilizado em outros contextos
   public function getUserAttribute($attribute){

       if(isset($this->attributes[$attribute])){
           return $this->attributes[$attribute];
       }

       throw new Exception('Attribute not found');

   }

}

Final considerations

Before finishing I would like to point out some points:

  • If the attributes grow, simply add a new item in the array passed to User and a new validator for this item.

  • As you can see, the classes will not be modified. The additions will be made in the configuration of the objects.

02.10.2018 / 03:33