DZone
Web Dev Zone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
  • Refcardz
  • Trend Reports
  • Webinars
  • Zones
  • |
    • Agile
    • AI
    • Big Data
    • Cloud
    • Database
    • DevOps
    • Integration
    • IoT
    • Java
    • Microservices
    • Open Source
    • Performance
    • Security
    • Web Dev
DZone > Web Dev Zone > DI Factories for Slim Controllers

DI Factories for Slim Controllers

Check out one way to implement a Dependency Injection factory to help augment your controllers in PHP's Slim framework.

Rob Allen user avatar by
Rob Allen
·
May. 12, 16 · Web Dev Zone · Tutorial
Like (2)
Save
Tweet
4.08K Views

Join the DZone community and get the full member experience.

Join For Free

When using classes for route actions in Slim 3, I recommend using a single class for each route. However, you can use a single class for multiple routes.

To register a class method to a route, you pass a string as the route callable where the class name is separate from method by a colon like this:

$app->get('/list', 'MyController:listAction');


Slim will retrieve MyController from the DI container and then call the listAction method using the usual signature:

function (Request $request, Response $response, $args = []) : Response;


If you don't specify a method, then Slim will see if it treats the class as a callable, so you can implement __invoke() and then register the route like this:

$app->get('/list', 'MyController');


and Slim will call MyController::__invoke() for you.

Writing a DI Factory for Your Class

Usually your controller action will need some dependencies in order to work, such as access to a service layer class, or ORM's entity manager.

To handle this, you should inject the dependency in your controller's constructor by writing a factory for the DI container. This sounds scary and complicated, but a factory is just another way of saying "a function that instantiates an object". This is the simplest DI container factory we can write for MyController:

// Retrieve container instance
$container = $app->getContainer();

// Register MyController
$container['MyController'] = function ($c) {
 return new MyController();
};


The closure is the factory and, as you can see, it simply returns an new instance of MyController. It is registered with Slim's default DI container by assigning the closure to an array key (['MyController']), and it is vital that the string you use here is the same as the string you use before the colon in the route configuration ('MyController:list').

Injecting the dependencies

To inject the dependencies, we register them with the DI container too as factories and then retrieve them in our controller factory.

Firstly, register a dependency:

$container['DatabaseService'] = function ($c) {
 return new DatabaseService();
};


Now we can use this in our controller factory. To do this, note that the factory closure has a parameter, $c, which is the DI container itself. This means we can retrieve anything that's registered with the DI container by using the get() method.

Hence we update our controller factory like this:

$container['MyController'] = function ($c) {
 $dbService = $c->get('DatabaseService');
 return new MyController($dbService);
};


The MyController constructor now receives our dependency and can store it to a class property ready for use in the route action method like this:

final class MyController
{
 private $dbService;
 public function __construct($dbService)
 {
 $this->dbService = $dbService;
 }

 public function listAction($request, $response, $args)
 {
 $dataArray = $this->dbService->fetchData();
 return $response->withJson($dataArray);
 }
}


There are numerous advantages to doing this. The main one for me is that there are no surprise dependencies anymore. You can look at the constructor and know exactly which classes that class needs to do its job. You can also test it more easily, which is beneficial!

I prefer to use one class for each route action, as I can ensure that the dependencies that are injected are the correct ones for this action. When using multiple action methods in a controller class, you start needing to inject classes that are only used for just one or two of the actions and this is inefficient, especially if those dependencies are relatively expensive to construct. There are ways around this if you use a more powerful DI container, such as Zend-ServiceManager, though.

Factory (object-oriented programming)

Published at DZone with permission of Rob Allen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Fintech and AI: Ways Artificial Intelligence Is Used in Finance
  • Real-Time Supply Chain With Apache Kafka in the Food and Retail Industry
  • Use Lambda Function URL To Write a Serverless App Backed by DynamoDB
  • How to Minimize Software Development Cost

Comments

Web Dev Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • MVB Program
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends:

DZone.com is powered by 

AnswerHub logo