0

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();
GothicAnatomist
  • 146
  • 4
  • 15

1 Answers1

0

If you want to call the test method the syntax is :

 $app->get('/', TestController::class .':test');
 // or 
 $app->get('/', 'TestController:test');

rather than

$app->get('/', TestController::class ,':test');

cf https://www.slimframework.com/docs/v3/objects/router.html#container-resolution

R. Martin
  • 411
  • 2
  • 11