davidjh
davidjh

Reputation: 417

Slim php - access container from middleware

I am trying to access the $container from my middleware, but i am not getting much luck.

In my index.php file I have

require '../../vendor/autoload.php';
include '../bootstrap.php';

use somename\Middleware\Authentication as Authentication;

$app = new \Slim\App();
$container = $app->getContainer();
$app->add(new Authentication());

And then I have a class Authentication.php like this

namespace somename\Middleware;

class Authentication {
  public function __invoke($request, $response, $next) {
    $this->logger->addInfo('Hi from Authentication middleware');

but i get an error

Undefined property: somename\Middleware\Authentication::$logger in ***

I have also tried adding the following constructor to the class but I also get no joy.

 private $container;

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

Could anyone help please?

Upvotes: 0

Views: 2823

Answers (2)

jmattheis
jmattheis

Reputation: 11115

I disagree with Ali Kaviani's Answer. When adding this PHP __magic function (__get), the code will be a lot more difficult to test.

All the required dependencies should be specified on the constructor. The benefit is, that you can easily see what dependencies a class has and therefore only need to mock these classes in unit-tests, otherwise you would've to create a container in every test. Also Keep It Simple Stupid

I'll show that on the logger example:

class Authentication {
    private $logger;

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

    public function __invoke($request, $response, $next) {
        $this->logger->addInfo('Hi from Authentication middleware');
    }
}

Then add the middleware with the logger parameter to the container:

$app = new \Slim\App();
$container = $app->getContainer();
$container['MyAuthenticator'] = function($c) {
    return new somename\Middleware\Authentication($c['logger']);
};

Note: the above registration to the container could be done automatically with using PHP-DI Slim (but that should be also slower).

Upvotes: 0

Ali Kaviani
Ali Kaviani

Reputation: 321

Best Practice to Middleware Implementation is Something like this :

Place this code inside your dependency section :

$app = new \Slim\App();
$container = $app->getContainer();
/** Container will be passed to your function automatically **/
$container['MyAuthenticator'] = function($c) {
    return new somename\Middleware\Authentication($c);
};

then inside your Authentication class create constructor function like you mentioned : namespace somename\Middleware;

class Authentication {
    protected $container;

    public function __invoke($request, $response, $next)
    {
        $this->container->logger->addInfo('Hi from Authentication middleware');
    }

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

    /** Optional : Add __get magic method to easily use container 
        dependencies 
        without using the container name in code 
        so this code : 
        $this->container->logger->addInfo('Hi from Authentication middleware'); 
        will be this :
        $this->logger->addInfo('Hi from Authentication middleware');
    **/

    public function __get($property)
    {
        if ($this->container->{$property}) {
            return $this->container->{$property};
        }
    }
}

After inside your index.php add Middleware using name resolution like this:

$app->add('MyAuthenticator');

Upvotes: 4

Related Questions