Case of use of the SRP concept in a real application

Asked

Viewed 150 times

5

I’m studying some concepts of OOP and I see a lot about the issue of SRP, "separating actions into classes etc". at the level of testing, I decided to create a small system for registering users in order to test the knowledge, only that I came across some questions

1 - I must separate the validation logic and the CRUD part into classes separated?

2 - It is the user’s responsibility to validate himself?

2.1 - User class may be responsible for "accumulating" validation errors?

3 - The user is responsible for saving himself?

4 - What would this example look like with thousands of attributes? use a loop in the setters methods?

What I concluded, based on the studies:

  • I must use 3 classes, User, Uservalidator and Usercrud, because in my understanding they are different "actions"

  • The User class would be the most "abstract", relating validation and integration with the database.

  • Should I create a second class called Uservalidator that would be responsible for the validation rules and can be coupled to some validation library? (Respect/rakit)

  • And finally, it would create a last class called Usercrud, which would inherit the methods of another class called "crudModel", responsible for integration with the database

Code example:

class User {

    private $name;
    private $age;

    function __construct () {

        $this->userValidator = new userValidator;
        $this->userCRUD = new userCRUD;
    }

    function setName($name) {

        if($this->userValidator->validateName($name))
            $this->name = $name;
    }

    function setAge($age) {

        if($this->userValidator->validateAge($age))
            $this->age = $age;
    }

    function hasErrors () {
        return $this->userValidator->hasErrors();
    }

    function Save () {

        $user_data['name'] = $this->name;
        $user_data['age'] = $this->age;

        return $this->userCRUD->create($user_data);
        // retorna true para salvo e falso para erro
    }

}

-

    class UserValidator {

    private $error_bag;

    public function validateName ($name) {

        if(strlen($name) > 5)
            return 1;
        else 
            $this->setValidationError('name', 'Nome deve ser maior que 5');
    }

    public function validateAge ($age) {

        if(is_numeric($age))
            return 1;
        else 
            $this->setValidationError('age', 'Idade inválida');
    }

    private function setValidationError ($error, $error_msg) {
        $this->error_bag[$error] = $error_msg;
    }

    private function getValidationErrors() {
        return $this->error_bag;
    }

    public function hasErrors () {

        if( empty($this->getValidationErrors()) )
            return false;
        else
            return $this->getValidationErrors();
    }
}

Code call:

    $User = new User;
    $User->setName('Fulano de Tal');
    $User->setAge(50);

    if($User->hasErrors()) {
        // exibe os erros na tela
        print_r($User->hasErrors());

    } else {
        // salve o usuario
        $saveUser = $User->Save();
        var_dump($saveUser);
    }

1 answer

4

In search of SRP (Single Responsibility Principle)

Follow the answers to your questions.

1 - I must separate the validation logic and the CRUD part into separate classes?

Yes. It is better to separate the validation of the part that makes the CRUD operations, because they are separate operations.


2 - It is the user’s responsibility to validate himself?

Not necessarily. You can create a component to validate a user, as this would run against SRP.

2.1 - User class may be responsible for "accumulating" validation errors?

Complementing the previous answer: the validation component would be a more appropriate place for this information.


3 - The user is responsible for saving himself?

It is better to create a class to save a user, because everything is more separate. When a user saves the SRP itself is being violated, because the object has two responsibilities: contain the user information and persist in the database. This type of approach is called Active Record and it ends up mixing things up, so it is better to avoid it to be able to follow the SRP.


4 - What would this example look like with thousands of attributes? use a loop in the setters methods?

From what I understand, your question on this issue is in the case of a lot of data. If your User object has multiple data, you can pass an array with the data to avoid an immense amount of getters and setters. This question is answered in more detail here.


Your example of the User class

I noticed that your code contains some dependencies on the User object:

function __construct () {

    $this->userValidator = new userValidator;
    $this->userCRUD      = new userCRUD;

}

This implementation could improve if you pass the User object to the objects and don’t make it receive them, for example:

class UserValidator
{

    public function validate(User $user)
    {
        // Pegar os dados do objeto user e validá-los aqui
    }

}

class UserCrud
{

    public function save(User $user)
    {
         // Salva e edita o usuário
    }

    public function delete(User $user)
    {
         // Deleta o usuário
    }

}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.