0

I am using http://container.thephpleague.com as my Dependency Injection Container. I am making project in MVC and I am trying to not break MVC pattern.

I am loading Database, Json, etc. classes from DI Container (defined before routing, etc.), but I need models for every controller. Is this right way how to load Models with their own dependencies inside Controller?

Controller:

abstract class Controller
{
    protected $di;
    protected $db;
    protected $latte;
    protected $json;
    //etc...

    public function __construct(League\Container\Container $container)
    {
        $this->di = $container;
        $this->db = $container->get('database');
        $this->json = $container->get('json');
        //etc...

        $this->setup();
    }
}

class ApiController extends Controller
{
    function setup()
    {
        $this->model = new ApiModel($this->di);
    }

    public function showGames()
    {
        $this->latte->render("random-view.latte", $this->model-getGames());
    }
}

Model:

class Model
{
    protected $db;
    protected $json;

    public function __construct(League\Container\Container $container)
    {
        $this->json = $container->get('json');
        $this->db = $container->get('database');
    }
}
class ApiModel extends Model
{
    /**
     * Get games
     * @return mixed
     */
    public function getGames()
    {
        //db queries etc...
    }
}

Something saying me, that this is not right way.

  • 1
    I think this is opinion based. My opinion is that you’re doing it wrong: the whole point of dependency injection is to make the dependencies explicit. By having the container be the dependency you’re actively avoiding that. It’s like a Service Locator antipattern – ishegg Oct 14 '17 at 14:37
  • You are not using it as DI container. You are not supposed to pass it around as some global god-object. And to answer your question: **NO**, "model" is not not even a class, but a layer. Basically, you are doing it all wrong. – tereško Oct 14 '17 at 16:31
  • And how I can make it right? –  Oct 14 '17 at 18:28
  • Here are some very good resources to study. They will give you the answer to the question "How can I make it right?". [The Clean Code Talks - Don't Look For Things!](https://www.youtube.com/watch?v=RlfLCWKxHJ0), [PHPNW15: James Mallison - Dependency Injection and Dependency Inversion in PHP](https://www.youtube.com/watch?v=Ojsn11XY0X8&feature=youtu.be), [Managing Class Dependencies: ..., Part 1](https://www.sitepoint.com/managing-class-dependencies-1/), [Managing Class Dependencies: ..., Part 2](https://www.sitepoint.com/managing-class-dependencies-2/), –  Oct 15 '17 at 19:33
  • [PHP - The best way to load Database object from Model, but to have only one instance?](https://stackoverflow.com/questions/9525177/php-the-best-way-to-load-database-object-from-model-but-to-have-only-one-inst), [How should a model be structured in MVC?](https://stackoverflow.com/questions/5863870/how-should-a-model-be-structured-in-mvc/5864000#5864000), [Understanding MVC](https://stackoverflow.com/questions/10675512/understanding-mvc/10685095#10685095), –  Oct 15 '17 at 19:35
  • [Building a Domain Model – An Introduction to Persistence Agnosticism](https://www.sitepoint.com/building-a-domain-model/), [Building a Domain Model – Integrating Data Mappers](https://www.sitepoint.com/integrating-the-data-mappers/), [An Introduction to Services](https://www.sitepoint.com/an-introduction-to-services/), [Handling Collections of Aggregate Roots – the Repository Pattern](https://www.sitepoint.com/handling-collections-of-aggregate-roots/). –  Oct 15 '17 at 19:36
  • As for the DIC, the whole DIC codes should be found only in the entry point of your app (index.php or bootstrap.php). At least the [Constructor Injection](http://container.thephpleague.com/3.x/constructor-injection/) page shows you exactly how to create and pass the required dependencies as arguments. –  Oct 15 '17 at 19:46
  • And here is another great website with articles regarding MVC: [Tom Butler's Programming Blog. MVC, PHP, Best practices](https://r.je/). –  Oct 15 '17 at 19:57
  • Thanks, But what I am doing exactly wrong? I am not supposed to use model for controller? I am not supposed to use DI Container as global "container" for all my models what i need use almost everywhere? –  Oct 15 '17 at 21:36
  • Well, that's the problem: you are making all... wrong. So, I suggest you to take it step by step. Forget about the DIC for the moment and concentrate yourself on the study of how the MVC should be implemented. After that you can think of how to use the DIC, since this is the easiest part. In principle, the **M** from MVC means **_model layer_** and consists of: domain objects (the so called "models"), data mappers and, eventually, repositories and services. What are they and how can you use/implement/combine them? Just read the links above and you'll understand. –  Oct 15 '17 at 23:52
  • As for the DIC: In your MVC you'll have to instantiate objects like controllers, session, request, domain objects, data mappers, etc. Some of them will be dependencies, passed as arguments to the other objects. The DIC is responsible with the creation of all the objects and passing of all dependencies. And this will happen, as said, only at the app's entry point. So, the DIC will not be passed as dependency to no object. The first two links gives you the very good argumentation about why this should not happen. –  Oct 16 '17 at 02:23
  • Sure but when i not pass $container variable to my controller how can I instantiate stuff like Db connection? So the way how you saying is to add even controllers to DIC and after that just call Controller what will have all dependencies automaticaly solved? –  Oct 16 '17 at 17:21
  • Exactly. But, let me be clearer. Let's say, the controller have no dependencies. Then you don't really need to use DIC to create a controller instance; you can instantiate it as normal. –  Oct 16 '17 at 23:54
  • Now, let's say the controller has a dependency. Then the constructor of the `Controller` class will be: `public function __construct(PDO $db) { $this->db = $db; }`. How would you proceed then? For example: Step 1 - Add PDO to DIC: `$container->add('alias_for_db', PDO::class);`; Step 2 - Add controller to DIC and assign the db dependency as well: `$container->add('alias_for_controller', ApiController::class)->addArgument('alias_for_db');`. Like showed in [Basic Usage - Container](http://container.thephpleague.com/3.x/basic-usage/). –  Oct 17 '17 at 00:28
  • Step 3 - instantiate controller: `$controller = $container->get('alias_for_controller');`. Step 4 - call controller action as usual. This way the DIC will automatically create a controller instance and resolve its db dependency. And this code should be only at app's entry point (index.php or so). This is a start... Now, in the link you'll find further the `share()` method of DIC. That's for the case that you want DIC to create only one instance of an object, no matter how many times you would call DIC's `get()`. –  Oct 17 '17 at 00:43
  • @aendeerei Thanks, I finnally got it. But I have last question. What if I have model what is used in my controller like I have in original question and this model have his own dependencies? Best way how to do it is not push all models to DIC on start or yes? Because When I have about 30 controllers and 30 models site will be loading much longer when I will pushing all stuff what i dont need inside DIC. Am I supposted to add into DIC just controller and model after I get right one from Router? –  Oct 17 '17 at 16:16
  • That's great. And this is a very good question. Conform to the 1st links package, no dependencies (objects) should be created using `new`, inside a class. They should be injected. So, the models should ideally be injected as dependencies of the controllers. Now, if you choose to register the corresponding models only to the required controller in the DIC, or to register all models to all controllers, before calling the controller action... that would be a great stackoverflow question. –  Oct 17 '17 at 18:58
  • Technically, it would be better to register only the needed resources per request. Practically, I think it depends on the MVC structure and on the libraries/components that are used. So,... I would be glad to read the answers of other users on this question. Please notify me and I will also put a bounty of 100 reputations on it. –  Oct 17 '17 at 18:59
  • @aendeerei you can summarize what you wrote in your comments and send it as a reply. I will mark it as closed. Thanks for help. –  Oct 17 '17 at 19:21
  • @D3admau5 You mean I should write an answer with the comment's summary, which you will then mark as "accepted"? This would be not good, because your question is somehow too broad, the answer to it beeing composed from all the materials I gave you. I just hope that my comments and the ones of the other users gave you the right direction. Good luck! –  Oct 17 '17 at 19:34
  • @aendeerei yes they directed me right, so I just leave question unanswered? –  Oct 18 '17 at 06:49
  • @D3admau5 Yes, it's no problem. –  Oct 18 '17 at 11:20

0 Answers0