Reputation: 593
I'm using Slim, and php-di for the container, I've been trying to figure out how to autowire the dependencies without success.
I have App\Models\Planner.php
that I'd like to inject into App\Controllers\MealPlanner.php
, along with various other classes and models that are called by different endpoints/methods/actions.
Right now on Services.php, I'm creating 4 services 2 which will get passed to other classes, and 2 factories which are the Planner.php and MealPlanner.php which is called in the router on index.php.
Now that MealPlanner is defined as a service, it can be called directly i.e from $app->any('/mealplanner/{action}', \MealPlanner::class);
, if I remove the $app->set('MealPlanner', ...)
I'll get "Callable MealPlanner does not exist", why is it callable there without accessing the container?
Secondly, let's say I'd like to inject Fruits class onto MealPlanner along with the Planner.php, to do that I'd have to add a new service $container->set("Fruits", (){ return App\Models\Fruits.php(PDO $db, $UserId) })
then on MealPlanner service I'd have to pass the fruits container there, and then on MealPlanner controller it'd now be:
public function __construct(App\Models\Planner $planner, App\Models\Fruits $fruits)
Personally it's tiresome to have to pass them through the service container, and then have to change them on the controller, I'm probably misunderstanding something here..
Let's say I decided to drop the code above, and instead "slim will instantiate the container" instead, MealPlanner.php would now be
namespace App\Controllers;
use Psr\Container\ContainerInterface;
class MealPlanner extends InvokeAction {
public function __construct(ContainerInterface $container){
$this->container = $container;
}
public function init($request, $response, $args){
// return something
}
}
I'd have to remove the MealPlanner factory from the container, so the route class definition would stop working, and I'd have to use it's absolute path for it to work $app->any('/mealplanner/{action}', \App\Controllers\Planner::class);
, now all the services like 'Database', and 'Planner' is accessible through the container, but I'll still have to create the services, like Fruits, so not grasping how auto-wiring works since they're not defining absolute paths when type-hinting.
Upvotes: 2
Views: 866
Reputation: 3189
I've created a framework that marries Slim 4 and Eloquent ORM called Willow. Here's how I use PHP-DI:
<?php
declare(strict_types=1);
namespace Willow\Main;
use DI\ContainerBuilder;
use Slim\Factory\AppFactory;
class App
{
public function __construct()
{
// Set up Dependency Injection
$builder = new ContainerBuilder();
// Read in each config file to inject. See db.php below as an example
foreach (glob(__DIR__ . '/../../config/*.php') as $definitions) {
$builder->addDefinitions(realpath($definitions));
}
$container = $builder->build();
// Get an instance of Slim\App and inject the container.
AppFactory::setContainer($container);
$app = AppFactory::create();
}
}
<?php
declare(strict_types=1);
use Illuminate\Database\Capsule\Manager as Capsule;
use Psr\Container\ContainerInterface;
// By returning this array it sets up Capsule::class to be injected via DI
return [
Capsule::class => function (ContainerInterface $c) {
$eloquent = new Capsule;
$eloquent->addConnection([
'driver' => env('DB_DRIVER') ?? 'mysql',
'host' => getenv('DB_HOST'),
'port' => getenv('DB_PORT') ?? '',
'database' => getenv('DB_NAME'),
'username' => getenv('DB_USER'),
'password' => getenv('DB_PASSWORD'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => ''
]);
// Make this Capsule instance available globally via static methods
$eloquent->setAsGlobal();
// Setup the Eloquent ORM...
$eloquent->bootEloquent();
// Set the fetch mode to return associative arrays.
$eloquent->setFetchMode(PDO::FETCH_ASSOC);
return $eloquent;
}
];
Upvotes: 3