I'm trying to switch from the pimple container that comes bundled with Slim, to PHP-DI and I'm having an issue with getting the autowiring to work. As I'm restricted to using PHP 5.6, I'm using Slim 3.9.0 and PHP-DI 5.2.0 along with php-di/slim-bridge 1.1.
My project structure follows along the lines of:
api
- src
| - Controller
| | - TestController.php
| - Service
| - Model
| - ...
- vendor
- composer.json
In api/composer.json
I have the following, and ran composer dumpautoload
:
{
"require": {
"slim/slim": "3.*",
"php-di/slim-bridge": "^1.1"
},
"autoload": {
"psr-4": {
"MyAPI\\": "src/"
}
}
}
My api/src/Controller/TestController.php
file contains a single class:
<?php
namespace MyAPI\Controller;
class TestController
{
public function __construct()
{
}
public function test($request,$response)
{
return $response->write("Controller is working");
}
}
I initially tried to use a minimal setup to get the autowiring working, just using the default configuration. index.php
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require '/../../api/vendor/autoload.php';
$app = new \DI\Bridge\Slim\App;
$app->get('/', TestController::class, ':test');
$app->run();
However, this returned the error:
Type: Invoker\Exception\NotCallableException
Message: 'TestController'is neither a callable nor a valid container entry
The only two ways I could get it to work, is to place the TestController
class in index.php
directly (which makes me think PHP-DI isn't playing well with the autoloader) or to use the following extension of \DI\Bridge\Slim\App
. However, as I need to explicitly register the controller class, this kinda defeats the point of using autowiring (unless I'm missing the point):
use DI\ContainerBuilder;
use Psr\Container\ContainerInterface;
use function DI\factory;
class MyApp extends \DI\Bridge\Slim\App
{
public function __construct() {
$containerBuilder = new ContainerBuilder;
$this->configureContainer($containerBuilder);
$container = $containerBuilder->build();
parent::__construct($container);
}
protected function configureContainer(ContainerBuilder $builder)
{
$definitions = [
'TestController' => DI\factory(function (ContainerInterface $c) {
return new MyAPI\Controller\TestController();
})
];
$builder->addDefinitions($definitions);
}
}
$app = new MyApp();
$app->get('/', ['TestController', 'test']);
$app->run();