MVC Objects, Models, and Data Access

I have a theoretical question that I hope someone can help me figure out.

I am currently writing a simple web application in PHP using the MVC design pattern. I have seen and read several manuals on this subject, but they are usually either too complicated or too simplified.

So, I currently have a simple User model:

 class User { private $username; private $group; //user, admin, etc // getters } 

I also have a simple Database class that implements this class:

 interface DatabaseInterface { public function connect(); public function disconnect(); public function prepare($sql = null); public function execute($params = array()); public function rowCount(); public function fetch(); } 

My question is: how to associate this Database class with the filling of the User class?

At the moment, I have another class called UserDAO , which is passed a reference to the Database class in its constructor, and it has a function called ValidateUser() , which then uses the interface methods described above to verify the user to the database.

 class UserDAO { private $database; public function __construct($database) { $this->database = $database; } public function validateUser($username, $password) { $this->database->prepare('SELECT * FROM users WHERE...'); .... return true/false; } } 

And now I pass the UserDAO object to the User class through the constructor, and also add another ValidateUser() method to the User class, which basically just calls the ValidateUser() method in the UserDAO > class.

New User class:

 class User { private $username; private $group; //user, admin, etc private $userDAO; public function __construct($userDAO) { $this->userDAO = $userDAO; } public function validateUser($username, $password) { if($this->userDAO->validateUser($username, $password)) { // set stuff that i need return true; } return false; } // getters } 

Something about this I don't like. Can someone help me understand how this process usually proceeds?

Also, the Database class usually remains static, so can I just call the connection using something like Database::instance() ? Now I create one database object at the top of the PHP page and pass it.

Feel free to leave me a comment if something is unclear, and I will try to fix it as soon as possible.

Thank you for watching and sorry for the length of the message.

+4
source share
4 answers

It depends on how last your decision will be.

Singleton

The "oldest" version must have a static connection, called everywhere. You understand this using singleton :

 class database { private $instance = NULL; private function __construct() public function getDb() { return $this->instance?: $this->instance = new database(); } } 

Registry

The second, newer solution is to use the registry : You may have a base class that extends with all other classes and provides methods for calling like

 $this->getRegistry()->getDb 

Usually the registry is populated at the beginning of your script, for example. in bootstrap. The advantages are that you can better unify components since there are no static parts, and you can define different registries for dev and production environments ...

Dependency Injection

The third, β€œnewest” and best method in dependency injection . Usually you will have some kind of infrastructure that does this for you. The idea is that whenever you call the class constuctor, all dependencies, such as db connections, are introduced by the framework.

Thus, you can easily define "Custom DB and Redis. The store needs DB, Config and FTP" ... Although this is an overhead for small projects, it helps a lot with huge and fully tested ones.

DI works well if you upgrade to several databases once (for example, one master and several slaves ), since you can provide each part of the database code that must be executed without changing a single line of code.

+3
source

When you transfer the database connection to the UserDOA object, you create a dependency. The UserDOA object now depends on the database instance.

Without a doubt, the best way to manage these dependencies (not only with your UserDOA, but also with your other DOA classes and more) through the IoC container (control inversion) using Injection Dependency Injection .

Enabling dependencies allows you to register the components / classes (and the arguments necessary to create an instance of the class object) inside the container, and then add the database instance (in your case) to any class you specify. This makes the code much more manageable, extensible, loosely coupled and follows SOLID principles.

One dependency injection container that I would recommend is the Symfony dependency injection component , which has been extracted and can be used on its own.

+1
source

For recording, for a business project, making an anemic model is practically the only way.

So, instead of creating a bloated model (or domain object) with several members / operators / functions, we have a single model with only a field definition, and we divided the classes with services.

a) the model classes should be lightweight and should change if the project model changes (for example, if we add a new field to the database table). Typically, a model is an entity (table mirror)

b) the dao class (one of the services) executes crud. As a service, it can be static (if not, it should be), so its call should be simple:

 public function validateUser($username, $password) { if(UserDAO::validateUser($username, $password)) { // set stuff that i need return true; } return false; } 

However, for this particular case, the validateUser function is more associated with LOGIC (a class that may change as business conditions change). Thus, we can create a new class of service that performs validation

 class UserLogic { public static validateUser($user) { $userInDb=UserDao::getUser($user->idUser); // here goes the logic // why?, because it could changes, for example, validating the date, attempts, if its active... if ($userInDb!=null && $userInDb->password=$user->password) { return true; } return false; } } 

And to call this function we used:

  $isValid=UserLogic::validateUser($someUser); 
0
source

Look at singletones like $ this-> db = DB :: getInstance ();

Example:

 class Database { // Store the single instance of Database private static $instance; private function __construct() { // connection here } public static function getInstance() { if (!self::$instance) { self::$instance = new Database(); } return self::$instance; } } $db = new Database(); // the old way, don't do this. $db = Database::getInstance(); // the singleton way - do this everywhere! it will always return the same object 
-1
source

Source: https://habr.com/ru/post/1485054/


All Articles