Naguib Ihab
Naguib Ihab

Reputation: 4506

Best design method to access container functions

I'm new to SLIM3 and followed the tutorial to get some functions in the container that I want to access from anywhere in the code. So here's my index.php file where I initalise everything:

<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

// Require for loading the vendor libraries installed by composer
require 'vendor/autoload.php';


$config['displayErrorDetails'] = true;
$config['addContentLengthHeader'] = false;

$app = new \Slim\App(["settings" => $config]);
$container = $app->getContainer();

// Monolog initalisation. To use it write: $this->logger->addInfo("what you want to write here");
$container['logger'] = function($c) {
    $logger = new \Monolog\Logger('eq_logger');
    $file_handler = new \Monolog\Handler\StreamHandler("logs/app.log");
    $logger->pushHandler($file_handler);
    return $logger;
};

// Database connections
$container['dbteacher'] = function ($c) {
    $pdo = new PDO($_SERVER['PGSQL_CONNECTION_STR']);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    return $pdo;
};
$container['dbagent'] = function ($c) {
    $pdo = new PDO($_SERVER['PGSQL_CONNECTION_STR_AGENT']);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    return $pdo;
};

$app->post('/{controller}/{function}', function (Request $request, Response $response) {
    $headers = $request->getHeaders();
    $params = $request->getParsedBody();

    $classname = $request->getAttribute('controller');
    $controller = new $classname($this->logger);
    $function = $request->getAttribute('function');

    $result = $controller->$function($params);

    $response->getBody()->write($result);
    return $response;
});

$app->run();

Here I can access logger by typing $this->logger, same goes for the dbteacher and dbagent, but I can only do that inside where these containers are created, when I am calling another function from a different class I want to be able to access them as well but I don't want to pass them in the parameter because that will be hard to maintain, I also though about having a config.php class that initalises these containers and the $app variable and extending it in every class I use but that doesn't sound right. What's the best way to approach this?

Upvotes: 1

Views: 311

Answers (1)

jmattheis
jmattheis

Reputation: 11135

You should use the functions of the dependency injection container (Pimple) which Slim3 uses.

That being said, I want to say that dynamically creating "controller"s isn't that nice, that abstraction shouldn't be there and you should just do $response->getBody()->write($result); or the simpler method $response->write($result); in every controller. Also, I don't see why a whole routing framework is needed for this construct.

But anyway if you want to stay with that solution, you can use Pimple, I'll explain that on an example.

You have several classes with different constructor parameter:

class A {
    public function __construct($logger) {}
}

class B {
    public function __construct($logger, $myHelper) {}
}

Firstly you add them all to the Pimple container:

$container['A'] = function($c) { // or $container[A::class] for type safety
    return new A($c['logger']);
};
$container['B'] = function($c) {
    return new A($c['logger'], $c['myHelper']);
};

And then you can get them in your route by calling get on the container on the app instance.

$app->post('/{controller}/{function}', function (Request $request, Response $response) {
    $headers = $request->getHeaders();
    $params = $request->getParsedBody();

    $classname = $request->getAttribute('controller');
    $controller = $this->getContainer()->get($classname);
    $function = $request->getAttribute('function');

    $result = $controller->$function($params);

    $response->getBody()->write($result);
    return $response;
});

Upvotes: 5

Related Questions