Zend Service Manager - исключение службы не найдено при попытке использовать phpdebugbar

Я пытаюсь использовать https://github.com/php-middleware/phpdebugbar в чистое приложение Zend Expressive Skeleton.

Я знаю, что инструкции на этой странице предлагают использовать эту конфигурацию DI (при использовании pimple):

$container[Psr\Http\Message\ResponseInterface::class] = new Zend\Diactoros\ResponseFactory();
$container[Psr\Http\Message\StreamFactoryInterface] = new Zend\Diactoros\StreamFactory();

Итак, я попытался использовать это (я использую Zend Service Manager):

return [
    'dependencies' => [
        'factories' => [
            Psr\Http\Message\ResponseInterface::class => new Zend\Diactoros\ResponseFactory(),
           'Psr\Http\Message\StreamFactoryInterface' => new Zend\Diactoros\StreamFactory(),
        ],
    ],
];

Но я сталкиваюсь со следующей ошибкой:

PHP Fatal error:  Uncaught Zend\ServiceManager\Exception\ServiceNotFoundException: Unable to resolve service "Psr\Http\Message\ResponseInterface" to a factory; are you certain you provided it during configuration? in /www/develop.expressive.centralsemi.com/htdocs/vendor/zendframework/zend-servicemanager/src/ServiceManager.php:687

Я также пробовал это:

return [
    'dependencies' => [
        'factories' => [
            Psr\Http\Message\ResponseInterface::class => new Zend\Diactoros\ResponseFactory(),
            Psr\Http\Message\StreamFactoryInterface::class => new Zend\Diactoros\StreamFactory(),
        ],
    ],
];

и это:

return [
    'dependencies' => [
        'factories' => [
            Psr\Http\Message\ResponseInterface::class => Zend\Diactoros\ResponseFactory::class,
            Psr\Http\Message\StreamFactoryInterface::class => Zend\Diactoros\StreamFactory::class,
        ],
    ],
];

Но все равно не повезло.

Правда, я не знаком с Zend/Diactoros, но я не понимаю, как Zend\Diactoros\ResponseFactory может быть фабрикой, у него нет метода __invoke(). Так что я чувствую, что это ядро ​​​​моей проблемы. Я должен создать свою собственную фабрику для этого? Я чувствую, что это не предназначенный способ сделать это.

Обратите внимание, я также пытался следовать этим инструкциям. И хотя ошибки нет, похоже, что она вообще не появляется: https://docs.zendframework.com/zend-expressive/v3/cookbook/debug-toolbars/

Я уверен, что упускаю какую-то ключевую часть, но что именно я упускаю?

Мой композитор.json:

{
    "name": "zendframework/zend-expressive-skeleton",
    "description": "Zend expressive skeleton. Begin developing PSR-15 middleware applications in seconds!",
    "type": "project",
    "homepage": "https://github.com/zendframework/zend-expressive-skeleton",
    "license": "BSD-3-Clause",
    "keywords": [
        "skeleton",
        "middleware",
        "psr",
        "psr-7",
        "psr-11",
        "psr-15",
        "zf",
        "zendframework",
        "zend-expressive"
    ],
    "config": {
        "sort-packages": true
    },
    "extra": {
        "zf": {
            "component-whitelist": [
                "zendframework/zend-expressive",
                "zendframework/zend-expressive-helpers",
                "zendframework/zend-expressive-router",
                "zendframework/zend-httphandlerrunner",
                "zendframework/zend-expressive-fastroute",
                "zendframework/zend-expressive-twigrenderer"
            ]
        }
    },
    "support": {
        "issues": "https://github.com/zendframework/zend-expressive-skeleton/issues",
        "source": "https://github.com/zendframework/zend-expressive-skeleton",
        "rss": "https://github.com/zendframework/zend-expressive-skeleton/releases.atom",
        "slack": "https://zendframework-slack.herokuapp.com",
        "forum": "https://discourse.zendframework.com/c/questions/expressive"
    },
    "require": {
        "php": "^7.1",
        "zendframework/zend-component-installer": "^2.1.1",
        "zendframework/zend-config-aggregator": "^1.0",
        "zendframework/zend-diactoros": "^1.7.1 || ^2.0",
        "zendframework/zend-expressive": "^3.0.1",
        "zendframework/zend-expressive-helpers": "^5.0",
        "zendframework/zend-stdlib": "^3.1",
        "zendframework/zend-servicemanager": "^3.3",
        "zendframework/zend-expressive-fastroute": "^3.0",
        "zendframework/zend-expressive-twigrenderer": "^2.0"
    },
    "require-dev": {
        "filp/whoops": "^2.1.12",
        "php-middleware/php-debug-bar": "^3.0",
        "phpunit/phpunit": "^7.0.1",
        "roave/security-advisories": "dev-master",
        "squizlabs/php_codesniffer": "^2.9.1",
        "zendframework/zend-expressive-tooling": "^1.0",
        "zfcampus/zf-development-mode": "^3.1"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/App/src/",
            "PhpDebugBar\\": "src/PhpDebugBar/src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "AppTest\\": "test/AppTest/"
        }
    },
    "scripts": {
        "post-create-project-cmd": [
            "@development-enable"
        ],
        "development-disable": "zf-development-mode disable",
        "development-enable": "zf-development-mode enable",
        "development-status": "zf-development-mode status",
        "expressive": "expressive --ansi",
        "check": [
            "@cs-check",
            "@test"
        ],
        "clear-config-cache": "php bin/clear-config-cache.php",
        "cs-check": "phpcs",
        "cs-fix": "phpcbf",
        "serve": "php -S 0.0.0.0:8080 -t public/",
        "test": "phpunit --colors=always",
        "test-coverage": "phpunit --colors=always --coverage-clover clover.xml"
    }
}

person d.lanza38    schedule 12.04.2019    source источник


Ответы (3)


попробуйте сначала создать псевдоним, а затем предоставить его фабрике

return [
    'dependencies' => [
        'factories' => [
            Psr\Http\Message\ResponseInterface::class => Zend\Diactoros\ResponseFactory::class,
           'Psr\Http\Message\StreamFactoryInterface' => Zend\Diactoros\StreamFactory::class,
        ],
        'aliases' => [
           ClassThatImplementsResponseInterface::class => Psr\Http\Message\ResponseInterface::class,
           ClassThatImplementsStreamFactoryInterface::class => 'Psr\Http\Message\StreamFactoryInterface',
        ]
    ],
];

ОБНОВЛЕНИЕ: Как обнаружил @d.lanza38, это конфигурация Райта.

return [
    'dependencies' => [
        'invokables' => [
            Zend\Diactoros\ResponseFactory::class => Zend\Diactoros\ResponseFactory::class,
            Zend\Diactoros\StreamFactory::class => Zend\Diactoros\StreamFactory::class,
        ],
        'aliases' => [
            Psr\Http\Message\ResponseFactoryInterface::class => Zend\Diactoros\ResponseFactory::class,
            Psr\Http\Message\StreamFactoryInterface::class => Zend\Diactoros\StreamFactory::class,
        ]
    ],
];
person Razvan Ionascu    schedule 15.04.2019
comment
Спасибо @Разван. Что я должен использовать вместо ClassThatImplementsResponseInterface::class и ClassThatImplementsStreamFactoryInterface::class? Я должен написать свою собственную реализацию? Я думал, это то, что Zend\Diactoros должен был предоставить. - person d.lanza38; 15.04.2019
comment
@ d.lanza38 Я думал, что это то, что ты собирался сделать. Скажи мне, что ты собираешься делать, чтобы я мог лучше понять. Если вы просто хотите создать собственный ответ (например, другой код: $this-›responseFactory-›createResponse(404)) попробуйте использовать этот docs.zendframework.com/zend-servicemanager/, поэтому вам не придется беспокоиться о пользовательских фабриках и предоставлять Zend\Diactoros\ResponseFactory конструктору класса из где вы хотите отправить ответ - person Razvan Ionascu; 16.04.2019
comment
Извините, если я немного неясен, я пытаюсь использовать php-middleware/phpdebugbar в свежем скелетном приложении Zend Expressive. Я наполовину смущен двумя совершенно разными наборами инструкций, которые я нашел, которые объясняют, как это сделать. Я не пытаюсь обслуживать ответ 404 или что-то в этом роде, просто пытаюсь заставить работать «php-middleware/phpdebugbar». В вашем ответе я не уверен, каковы мои эквиваленты ClassThatImplementsResponseInterface и ClassThatImplementsStreamFactoryInterface. - person d.lanza38; 16.04.2019

Я понял. Инструкции на странице https://docs.zendframework.com/zend-expressive/v3/cookbook/debug-toolbars/ верны. Единственным дополнительным шагом, который требуется, является добавление записей invokables и aliases в конфигурацию.

Мои были в /config/autoload/zend-expressive-tooling-factories.global.php:

return [
    'dependencies' => [
        'invokables' => [
            Zend\Diactoros\ResponseFactory::class => Zend\Diactoros\ResponseFactory::class,
            Zend\Diactoros\StreamFactory::class => Zend\Diactoros\StreamFactory::class,
        ],
        'aliases' => [
            Psr\Http\Message\ResponseFactoryInterface::class => Zend\Diactoros\ResponseFactory::class,
            Psr\Http\Message\StreamFactoryInterface::class => Zend\Diactoros\StreamFactory::class,
        ]
    ],
];

Изначально у меня был только раздел aliases, а не раздел invokables. Как только я добавил это, все просто заработало.

person d.lanza38    schedule 23.04.2019

Я пишу другой ответ, так как его легче читать. ХОРОШО. Я только что сделал новую установку Zend Expressive 3 и https://github.com/php-middleware/phpdebugbar. :

  1. композитор требует --dev php-middleware/php-debug-bar
  2. композитор дамп-автозагрузка
  3. Создан /config/autoload/debugbar.local.php
return array_merge(PhpMiddleware\PhpDebugBar\ConfigProvider::getConfig(), [
    'phpmiddleware' => [
        'phpdebugbar' => [
            'javascript_renderer' => [
                'base_url' => '/razvan.ionascu/ze-api/public',
            ],
            'collectors' => [
                DebugBar\DataCollector\ConfigCollector::class, // Service names of collectors
            ],
            'storage' => null, // Service name of storage
        ],
    ],
    'dependencies' => [

        'factories'  => [
            \PhpMiddleware\PhpDebugBar\PhpDebugBarMiddleware::class => \PhpMiddleware\PhpDebugBar\PhpDebugBarMiddlewareFactory::class,
            \DebugBar\DataCollector\ConfigCollector::class => \PhpMiddleware\PhpDebugBar\ConfigCollectorFactory::class,
            \PhpMiddleware\PhpDebugBar\ConfigProvider::class => \PhpMiddleware\PhpDebugBar\ConfigProvider::class,
            \DebugBar\DebugBar::class => \PhpMiddleware\PhpDebugBar\StandardDebugBarFactory::class,
            JavascriptRenderer::class => NewJavascriptRendererFactory::class,
        ],
    ],
]);

Чтобы это работало, вам нужно создать новый JavascriptRendererFactory. Текущий ищет неправильный ключ конфигурации, ConfigProvider::class вместо 'config' :

class NewJavascriptRendererFactory
{
    public function __invoke(ContainerInterface $container): JavascriptRenderer
    {
        $debugbar = $container->get(DebugBar::class);
        $config = $container->get('config');
        $rendererOptions = $config['phpmiddleware']['phpdebugbar']['javascript_renderer'];


        $renderer = new JavascriptRenderer($debugbar);
        $renderer->setOptions($rendererOptions);

        return $renderer;
    }
}
  1. добавлены следующие псевдонимы и фабрики в /config/atuoload/dependencies.global.php
'aliases'            => [
            \Psr\Http\Message\ResponseFactoryInterface::class              => ResponseFactory::class,
            \Psr\Http\Message\StreamFactoryInterface::class                => StreamFactory::class,
        ],
'factories' => [
...
\DebugBar\JavascriptRenderer::class => JavascriptRendererFactory::class,
...
],
  1. Добавлен новый конвейер в /config/pipeline.php
//only works in development mode
if (!empty($container->get('config')['debug'])) {
        $app->pipe(\PhpMiddleware\PhpDebugBar\PhpDebugBarMiddleware::class);
    }

Как я упоминал в предыдущем комментарии, я также настроил https://docs.zendframework.com/zend-servicemanager/reflection-abstract-factory/, поэтому мне не нужно создавать фабрику для каждой службы()

см. рабочую панель отладки здесь

person Razvan Ionascu    schedule 17.04.2019
comment
Большое спасибо @Razvan Ionascu за подробный ответ. Я все еще сталкиваюсь с проблемами, но позвольте мне немного взглянуть на это и выяснить, что у меня может быть по-другому. Но очень быстро, я просто хотел бы подтвердить несколько вещей. Я должен изменить 'base_url' => '/razvan.ionascu/ze-api/public', на 'base_url' => '/my/path/to/public',? Я должен изменить JavascriptRenderer::class => NewJavascriptRendererFactory::class, на \DebugBar\JavascriptRenderer::class => PhpDebugBar\Message\NewJavascriptRendererFactory::class,? - person d.lanza38; 17.04.2019
comment
И этот $renderer = new JavascriptRenderer($debugbar); имеет в виду DebugBar\JavascriptRenderer. И в /config/autoload/dependencies.global.php ResponseFactory::class и StreamFactory::class относятся к `Zend\Diactoros`, верно? - person d.lanza38; 17.04.2019
comment
Обратите внимание: я создал модуль PhpDebugBar\Message, который содержит NewJavascriptRendererFactory, как вы его определили. Модуль зарегистрирован и все. - person d.lanza38; 17.04.2019
comment
да, измените базовый URL-адрес на общедоступный, иначе активы из панели отладки не будут работать. Я думаю, что если вы измените то, что вы сказали, вы измените, это должно работать нормально. Если id не даст мне знать :). Удачи - person Razvan Ionascu; 18.04.2019
comment
Я создал новый проект Zend Expressive 3, точно следовал вашим шагам, но все еще получаю ту же ошибку «Невозможно преобразовать службу Zend\Diactoros\ResponseFactory в фабрику»; Вы уверены, что предоставили его во время настройки? У меня такое чувство, что моя проблема вращается вокруг PSR-17, и один пакет ожидает фабрики старой школы, использующие __invoke, а другой ожидает фабрики типа PSR-17. Я опубликую свой composer.json в своем вопросе для справки. Не могли бы вы сообщить мне, есть ли какие-либо различия между моим и вашим? - person d.lanza38; 22.04.2019
comment
Конечно. Вы также можете попробовать использовать это: docs.zendframework.com/zend-servicemanager/ чтобы у вас не было головной боли, связанной с фабриками. - person Razvan Ionascu; 23.04.2019
comment
Спасибо за совет. Мне нужно изучить это, чтобы я мог использовать его в будущем. Кроме того, похоже, что моя проблема все время была решена с помощью варианта вашего исходного ответа. Если вы просто обновите его с помощью кода в ответе, который я предоставил, я приму его как правильный ответ. - person d.lanza38; 23.04.2019