Best option for invoking model functionality in a PHP controller

I am creating a custom MVC environment using PHP. My problem is when I want to access any model class through the controller class. One of the ways I've seen is to do it through a registry design template using magic methods like get and set, although PHP get and set are considered bad practice for some. I read about dependency injection done through the container, but I don't see it working efficiently, because the container would have to call models, or it should contain models that could defeat the MVC target and create a massive superclass. Singleton is considered bad practice. Are there any solutions or improvements to the methods that I mentioned. It may just be my understanding, and knowledge of PHP needs to be improved.

I currently have this: router.php (loads controllor via a GET variable

<?php class router { function __construct() { if (file_exists("controller/".$_GET['url']."Controller.php")) { function __autoload($controller) { $controlinclude = "controller/".$controller.".php"; include $controlinclude; } $control = $_GET['url']."Controller"; new $control(); } else { // throw exception } } } ?> 

Hope it does

+4
source share
2 answers

First of all ... Do not put the startup script in the routing mechanism. You mix duties. You will be better off creating a separate class for this based on spl_autoload_register .

Neeext .. do no the complexity of operations on the constructor. This forces you to code a few unverifiable. Perhaps you should have something like:

 // you might want to replace $_GET with $_SERVER['QUERY_STRING'] later $router = new Router( $_GET['url'] ); // where 'default' is the name of fallback controller $controller_class = $router->get_controller( 'default' ); $method_name = $router->get_action( 'index' ); $model_factory = new ModelFactory( new PDO( ... ) ); $controller = new {$controller_class}( $model_factory ); $controller->{$method_name}(); 

Also, you should look into php namespaces . It makes no sense to end the class ...Controller to know where the class will be.

Good ... back to the Model.

There is a fairly common misconception regarding models in the web development community (I blame RoR for this mess). A model in MVC is not a class , but an application layer that contains many instances. Most instances belong to one of two types of classes. With the following responsibilities:

  • Domain Logic :

    Transactions with all calculations, calculations and all the detailed data about the domain. The objects in this group do not know where and how the data is stored. They only manage information.

  • Data access

    Usually made from objects that match the DataMapper pattern (do not confuse with ORM with the same name .. nothing to do). Responsible for storing data from domain objects and their receipt. Maybe in the database .. maybe not. Your SQL queries will be here.

In a semi-real-world situation (), it might look something like this (referring to the abowe code):

 class SomeController { // ... snip ... protected $model_factory = null; // ... snip ... public function __construct( ModelFactory $factory ) { $this->model_factory = $factory; } // ... snip ... public function action_foobar() { $user = $this->model_factory->build_object( 'User' ); $mapper = $this->model_factory->build_mapper( 'User' ); $user->set_id(42); $mapper->fetch($user); if ( $user->hasWarning() ) { $user->set_status( 'locked' ); } $mapper->store( $user ); } // ... snip ... } 

As you can see, there is no indication of how the data was saved. It doesn't even matter if the user account was new or already exists.

Some materials you may find useful

Video

Books:

+5
source

A large container for dependency injection is a pimple, which some of them may be considered a service locator. It uses php 5.3 closure to create a class that is used to create all project objects using lazy loading. So, for example, you can create a closure that contains code to initialize this object. Then you would use the DI get() container method, which in turn would cause a closure to create the object. Or just pass the object to you if it is already created.

 // simplified dic class class dic { protected $closures = array(); protected $classes = array(); public function addResource($name, Closure $initialization_closure) { $this->closures[$name] = $initialization_closure; } public function get($name) { if (isset($this->classes[$name]) === false) { $this->classes[$name] = $this->closures[$name](); } return $this->classes[$name]; } } //setup $dic = new dic(); $dic->addResource('user', function() { return new UserClass($some_args); }); $dic->addResource('userContainer', function() use ($dic) { return new UserContainerClass($dic->get('user')); }); // usage $userContainer = $dic->get('userContainer'); 

This allows you to maintain flexibility in the ability to change the way you create and create objects throughout the project, only by changing a very small amount of code.

+1
source

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


All Articles