2

Hi I am looking to handle slim repository pattern in the common pattern

like:

productRepositoryInterface 
productRepository
product
ProducCOntroller

How do I build that using dependency injection of SLIM

I have routing and it goes to the controller called ProductController

then in the controller, I want to get in the constructor the ProductRepo interface

my dependencies

$container['productController'] = function($c , ProductRepositoryInterface $productRepo) use ($app) {

    return new ProductController($c ,$productRepo);
};

$container['productsRepository'] = function($c) use ($app) {
    return new ProductRepository( $c->db );
};

but I Got in the controller constructor the following error:

 Catchable fatal error: Argument 2 passed to ProductController::__construct() must be an instance of ProductRepositoryInterface, none given

Product controller:

function __construct($c,ProductRepositoryInterface $repo)
{
    $this->c = $c;
    // grab instance from container
    $this->repository = $repo;
}
Tuz
  • 1,810
  • 5
  • 29
  • 58
  • 1
    Maybe you’re out-growing Slim if you’re now implementing patterns such as repositories? – Martin Bean Feb 01 '18 at 09:33
  • @MartinBean this is not absolutely true. With Slim and packages like Slim-Bridge you can still create low-to-medium applications. – dios231 Feb 02 '18 at 13:43
  • @dios231 I know it’s not “absolutely true”. That’s why I qualified my comment with _maybe_. Was just something for the OP to think about if they hadn’t of already. – Martin Bean Feb 02 '18 at 15:44

2 Answers2

2

By default slim passes only the container object to the constructor. Now you have two options.

First option: Grab the repo from the container.

Example pseudo code:

Register the container entry:

use App\Service\Product\ProductRepositoryInterface;
use App\Service\Product\ProductRepository;

$container[ProductRepositoryInterface::class] = function (Container $container) {
    $db = $container->get('db');
    return new ProductRepository($db);
};

Create a controller:

namespace App\Controller;

use Slim\Container;
use App\Service\Product\ProductRepositoryInterface;

class ProductController
{
    /**
     * @var ProductRepositoryInterface
     */
    private $productRepo;

    public function __construct(Container $container)
    {
        // grab instance from container
        $this->productRepo = $container->get(ProductRepositoryInterface::class);
    }

}

Second option: Clean dependency injection. Create a container entry for the controller and pass all dependencies directly.

use Slim\Container;
use App\Service\Product\ProductRepositoryInterface;
use App\Controller\ProductController;
use App\Service\Product\ProductRepository;

$container[ProductRepositoryInterface::class] = function (Container $container) {
    $db = $container->get('db');
    return new App\Service\Product\ProductRepository($db);
};

$container[ProductController::class] = function(Container $container)
{
    $productRepo = $container->get(ProductRepositoryInterface::class);
    return new ProductController($productRepo);
};

The controller

namespace App\Controller;

use Slim\Container;
use App\Service\Product\ProductRepositoryInterface;

class ProductController
{
    /**
     * @var ProductRepositoryInterface
     */
    private $productRepo;

    public function __construct(ProductRepositoryInterface $productRepo)
    {
        $this->productRepo = $productRepo;
    }

}
odan
  • 4,757
  • 5
  • 20
  • 49
0

As @Daniel O. mention Slim does not support clear Dependence Injection (specifically the Inversion Of Control principle). So with Slim you can only inject dependencies through the Service Locator pattern (which is an anti-pattern based on Mark Seemannn.).

So you have two solutions:

  1. Create a Poor Man's DI. (It's the second solution @Daniel. O provide)
  2. Use the Slim-Bridge. This package just adapt PHP-DI container into Slim so make the auto-wiring for you.

What you have to bear in mind is that Dependency Injection and DI-container are two different concepts.

  • Slim uses the Service-Locator pattern (Daniel O. first solution)
  • Daniel O. second solution is a Poor Man's Di
  • Slim-bridge is a clear Dependency Injection Container
dios231
  • 714
  • 1
  • 9
  • 21
  • It is not Slim who provide dependency injection management, it is Pimple, Slim default DI manager. Unfortunately Pimple does not support auto wiring so you either implement as @DanielO second solution (which is good although tedious when working with many classes) or use other dependency manager which support auto wiring such PHP-DI. However auto-wiring has overhead. – Zamrony P. Juhara Apr 05 '18 at 12:08