lundi 14 janvier 2019

PHP - Structuring a Slim3 web application using MVC and understanding the role of the model

I’m trying to create an authentication system in php with the Slim3 framework along with the Twig template system, and for the database I’m using MySQL with PDO. I’m also trying to implement it using a model view controller design pattern. However I’m having difficulty understanding how to use an MVC structure for a web application. I’ve looked at a plethora of explanations on the web and there doesn’t seem to be a clear cut answer. A lot of people say to to use a php framework such as Laravel, Symfony or CodeIgniter as they apparently employ an MVC like structure. However I would much rather keep things simple and to write the code manually rather than using a framework.

Currently there are two interpretations of MVC that I see. The first one being depicted in this diagram:

enter image description here

The other interpretation I’ve seen is this: (which is taken from this YouTube video)

enter image description here

I have done my research. Questions and answers such as this and this have been helpful. But I’m still not sure how I might structure my own applications, specifically indentifying and understanding the model aspect of MVC. I’ll now explain the register process of my authentication app. So you have an idea how my code is works.

Firstly I have an SQLQueries class that simply puts a series of SQL statements into functions. I then have a SQLWrapper class that has functions that can for example store a new users details inside the database. This class also calls functions from the SQLQueries class. I also have a ValidateSanitize class that has functions that cleans user input as well as checking if user input is valid in the form. These three classes I think are part of the model aspect of MVC but I'm not sure. I see a lot of other tutorials using a ‘User Model class’ but I can’t find the need for one in my application.

My views are simply Twig templates that display html, such as the homepage, register, login etc. I then have controllers. I intend to have multiple controllers that do different things. For now I’ve only implemented the AuthController which is responsible for Registering and Signing a user in.

So the first thing the AuthController does is to display the register form in a function called getRegisterForm. Once the user has submitted the form the postRegisterForm function takes that user input and assigns it to tainted variables.

public function postRegisterForm($request, $response)  
{
   $arr_tainted_params = $request->getParsedBody(); 

   $tainted_email = $arr_tainted_params['email'];  it a variable
   $tainted_username = $arr_tainted_params['username'];
   $tainted_password = $arr_tainted_params['password'];
   $tainted_password_confirm = $arr_tainted_params['password_confirm'];

Next all of the three previous classes as well as the database details are instantiated so their functions can be used in the AuthController:

$sanitizer_validator = $this->container->ValidateSanitize;
$sql_wrapper = $this->container->SQLWrapper;
$sql_queries = $this->container->SQLQueries;
$db_handle = $this->container->get('dbase');

The tainted user details are then cleaned with the sanitize_input function. The cleaned user details are then fed into the validate functions to make sure they don’t trigger any validation violations. The password is also hashed here:

$cleaned_email = $sanitizer_validator->sanitize_input($tainted_email, FILTER_SANITIZE_EMAIL); 
$cleaned_username = $sanitizer_validator->sanitize_input($tainted_username, FILTER_SANITIZE_STRING);
$cleaned_password = $sanitizer_validator->sanitize_input($tainted_password, FILTER_SANITIZE_STRING);
$cleaned_password_confirm = $sanitizer_validator->sanitize_input($tainted_password_confirm, FILTER_SANITIZE_STRING);

$hashed_cleaned_password = password_hash($cleaned_password, PASSWORD_DEFAULT); 

$sanitizer_validator->check_email_exists($cleaned_email);
$sanitizer_validator->validate_email($cleaned_email);
$sanitizer_validator->validate_username($cleaned_username);
$sanitizer_validator->validate_password($cleaned_password);
$sanitizer_validator→validate_password_confirm($cleaned_password_confirm);

Finally there is an if statement that checks to see if all validation error messages are empty. If they are we provide the SQLWrapper class with the database details as well as a SQLQueries class object. We then insert the users details into the database by calling the SQLWrapper classes store-details function. Finally we direct the user to the login page, so the user can sign into their newly registered account.

if ($sanitizer_validator->get_validate_messages('email_error') == ' ' && $sanitizer_validator->get_validate_messages('username_error') == ' '
    && $sanitizer_validator->get_validate_messages('password_error') == ' ' && $sanitizer_validator->check_passwords_match($cleaned_password, $cleaned_password_confirm ) == true
    && $sanitizer_validator->check_email_exists($cleaned_email) == false)
{   

    $sql_wrapper->set_db_handle($db_handle); 
    $sql_wrapper->set_sql_queries($sql_queries); 

     $sql_wrapper->store_details($cleaned_email, $cleaned_username, $hashed_cleaned_password);
     return $response→withRedirect($this→container→router→pathFor('login'));

}

However if any of the validate error messages are not blank, then we call the SanitiseValidate display_validate_messages which simply sets the messages into a session to be displayed on the register twig template. We then redirect back to the register page so the user can see the validation error messages.

else
  {
      $sanitizer_validator->display_validate_messages();
      return $response->withRedirect($this->container->router->pathFor('register'));
  }
}

So based on this structure of a user registering an account. Does this adhere to a clean simple MVC structure or do some changes need to be made? Do any of my classes take the role of a model? Any suggestions and tips regarding my structure will be appreciated.

The full application can be seen on my GitHub if that would be helpful. Note that this version is slightly older than the sample code I used in this question.

Aucun commentaire:

Enregistrer un commentaire