Инъекция зависимости не работает с League \ Route and League \ Container

Я сейчас создаю веб-приложение и столкнулся с проблемой с моим контроллером.

Я хочу отправить своему контроллеру мой файл League \ Plate \ Engine (зарегистрированный в моем контейнере), но у меня по-прежнему возникает та же ошибка: Argument 3 passed to App\Controller\Main::index() must be an instance of League\Plates\Engine, array given

Вот мои файлы:
dependencies.php

use League\Container\Container;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Yajra\Pdo\Oci8;
use League\Container\ReflectionContainer;

$container = new Container();

// Active auto-wiring
$container->delegate(
new ReflectionContainer
);

// Others dependencies
// ...

// Views
$container->add('view', function () {
$templates = new League\Plates\Engine();

$templates->addFolder('web', __DIR__ . '/templates/views/');
$templates->addFolder('emails', __DIR__ . '/templates/emails/');

// Extension
//$templates->loadExtension(new League\Plates\Extension\Asset('/path/to/public'));
//$templates->loadExtension(new League\Plates\Extension\URI($_SERVER['PATH_INFO']));

return $templates;
});

return $container;

routes.php

use League\Route\RouteCollection;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

$route = new RouteCollection($container);

// Page index
$route->get('/', 'App\Controller\Main::index');

// Others routes...

return $route;

main.php

namespace App\Controller;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use League\Plates\Engine;

class Main
{
public function index(ServerRequestInterface $request, ResponseInterface $response, Engine $templates) {
//return $response->getBody()->write($this->templates->render('web::home'));
return $response;
}
}

заранее спасибо


РЕДАКТИРОВАТЬ
Я добился прогресса.
Я расширил класс Main, чтобы расширить абстрактный класс BaseController, который выглядит следующим образом:

namespace App\Controller;

use League\Plates\Engine;

class BaseController
{
protected $templates;

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

Первая ошибка исчезает, но появляется другая. В основном классе я хотел бы использовать view объект, который я создаю в контейнере, но объект, переданный конструктору, является пустым:

main.php

class Main extends BaseController
{
public function index(ServerRequestInterface $request, ResponseInterface $response) {
echo '<pre>'.print_r($this->templates,1).'</pre>'; // Return an empty Plate Engine object
return $response->getBody()->write($this->templates->render('web::home'));
//return $response;
}
}

И это не объясняет, почему появляется первая ошибка


РЕДАКТИРОВАТЬ 2
После некоторого копания я наконец заставляю это работать, но я чувствую, что что-то не так.
Я заменил в контейнере термин view по пространству имен класса Engine:

$container->add('League\Plates\Engine', function () {
// The same as before
});

В main.php Я обновил функцию индекса следующим образом:

public function index(ServerRequestInterface $request, ResponseInterface $response) {
$body = $response->getBody();
$body->write($this->templates->render('web::home'));
return $response->withBody($body);
}

И страница не выдает ошибку 500 и HTML-файл отображается правильно.

Но что, если я хочу изменить шаблонный движок прут например ? Это будет означать, что мне нужно будет изменить весь вызов на $container->get('League\Plate\Engine'); от $container->get('What\Ever'); ? Это не очень практично!
Я наверное что-то пропустил!
И проблема снова возникнет, когда я захочу использовать свой объект PDO … или любой другой объект.

1

Решение

Итак, я решил свою проблему, зарегистрировав мои классы контроллеров в самом контейнере.

Например, для отображения страницы индекса Main класс называют index функция. В моем контейнере я звоню

$container->add('App\Controller\Main')
->withArgument($container->get('view'));

Подведем итог:

bootstap.php (вызывается index.php)

require __DIR__ . '/../../vendor/autoload.php';

$dotenv = new \Dotenv\Dotenv(__DIR__ . '/../');
$dotenv->load();

$config = new Config(__DIR__ . '/../config/');

$container = require __DIR__ . '/../dependencies.php';

$route = require __DIR__ . '/../routes.php';

$response = $route->dispatch($container->get('request'), $container->get('response'));
$container->get('emitter')->emit($response);

dependencies.php

$container = new Container();

// activate auto-wiring
$container->delegate(
new ReflectionContainer
);

// Others dependencies...

// Views
$container->add('view', function () {
$templates = new League\Plates\Engine();

$templates->addFolder('web', __DIR__ . '/templates/views/');
$templates->addFolder('emails', __DIR__ . '/templates/emails/');

// Extension
//$templates->loadExtension(new League\Plates\Extension\Asset('/path/to/public'));
//$templates->loadExtension(new League\Plates\Extension\URI($_SERVER['PATH_INFO']));

return $templates;
});

// THIS IS THE TRICK
$container->add('App\Controller\Main')
->withArgument($container->get('view'));
// others controllers...

return $container;

routes.php

$route = new RouteCollection($container);

// Page index
$route->get('/', 'App\Controller\Main::index');

// Others routes...

return $route;

Я понятия не имею, почему или как это работает!

2

Другие решения

Это работает, потому что вы регистрируетесь в контейнере вашего класса контроллера и сообщаете контейнеру о зависимости, внедряете ваш класс View в конструктор.

Строка, которую вы добавили здесь, делает это:


$container->add('App\Controller\Main')
->withArgument($container->get('view'));

Пример документации Hello World это прекрасно объясняет.

http://container.thephpleague.com/3.x/constructor-injection/

0

По вопросам рекламы [email protected]