2

I'm creating an application using the Slim 3 framework which basically consists of dynamically populating a series of dropdown select statements and then produces a table of calculated data based on the selections.

I was originally going to stick to an MVC layout, however in order to separate out the data access layer (each model only handling a single item of data) I decided to place the business logic into a service layer after reading Dependency Injection Slim Framework 3

It's structured as :

  • index.php - routing and DIC where routes are called by ajax from different web pages
  • /models - contain classes for each item of data used in each dropdown e.g. Country.class.php, Product.class.php etc...
  • /controllers - contain 2 classes InputController.class.php to handle the dropdowns and CalculateController.class.php to handle the calculations.
  • /views - contains php templates to return with the response using php-views
  • /services - service classes to handle business logic and return data to be passed to view by controller

In the DIC, i'm trying to avoid passing the container to other classes, however I've hit a situation where I'm not sure how to inject the dependencies properly.

In my index.php file, I have the following code:

//DIC
$container = $app->getContainer();

$container['view'] = function ($container) {
    return new \Slim\Views\PhpRenderer('src/views/');
};

$container['InputService'] = function($container){

    //questionable area
    $model1 = $container->get('model1');
    $model2 = $container->get('model2');
    $model3 = $container->get('model3');

    new InputService($model1, $model2, $model3);
}

$container['InputController'] = function($container){
    $service = $container->get('InputService');
    $view = $container->get('view');
    new InputController($InputService, $view);
}

When the particular web page loads, an initial ajax call is sent which requests 2 or 3 of the dropdown views (as the first 2/3 aren't dependent on other choices in certain circumstances). As such the InputService is injected with the 3 models. However, if I want to use the same service class to deal with the remaining dropdowns, how do I inject the right models?

A few thoughts I've had so far:

  • Inject all the models when instantiating the service, however this would mean a lot of redundant objects being created each time it's called.

    $container['InputService'] = function($container){
    //questionable area
    
    $model1 = $container->get('model1');
    $model2 = $container->get('model2');
    $model3 = $container->get('model3');
    $model4 = $container->get('model4');
    $model5 = $container->get('model5');
    $model6 = $container->get('model6');
    $model7 = $container->get('model7');
    $model8 = $container->get('model8');
    $model9 = $container->get('model9);
    
    new InputService( /*an array of the models*/ );
    }
    
  • Create a different service class for each subsequent dropdown, although doing this makes me wonder if I should drop the service layer and just put the business logic in the models. However, wouldn't it be better to have the model classes gathering the data from the db, not be concerned about how it's then manipulated as in the future different areas of business logic will use the same data for something else?

    controller1 > service1 > 3 models

    controller1 > service2 > 1 model

    controller1 > service3 > 1 model

    controller1 > service4 > 1 model ...

    or perhaps:

    controller1 > model1 > 3 other models

    controller1 > model5

    controller1 > model6 ...

  • Pass the container to the controller and inject dependency into service as needed for each call.

GothicAnatomist
  • 146
  • 4
  • 15
  • 2
    _...the model classes gathering the data from the db..._ is a bad idea. The domain objects (your "models") should have no knowledge about any persistence layer, or of the fact that their data is saved to or received from one. For this task you could make use of [data mappers](https://martinfowler.com/eaaCatalog/dataMapper.html) and [repositories](https://martinfowler.com/eaaCatalog/repository.html). –  Feb 13 '18 at 22:18
  • The last point is also bad: the container would become a [service locator](http://misko.hevery.com/2008/07/18/breaking-the-law-of-demeter-is-like-looking-for-a-needle-in-the-haystack/) for the controller, with multiple disadvantages. –  Feb 13 '18 at 22:18
  • @aendeerei Thank you for your comments. I've now implemented data mappers and a repository collection to separate the concerns of the models having the data and the mappers getting it. The model objects now being returned by the repository. Yes, the last point was my last resort as I didn't want the problems of a service locator. – GothicAnatomist Feb 15 '18 at 10:25
  • You are welcome. Yes, I saw that you were trying to avoid passing the container, but I wanted to give you a greater... "motivation". A bit more: [here](https://stackoverflow.com/questions/5863870/how-should-a-model-be-structured-in-mvc/5864000#5864000) is a good article on the model layer. Good luck. –  Feb 15 '18 at 11:27

0 Answers0