为了账号安全,请及时绑定邮箱和手机立即绑定

Symfony 5 从控制台命令生成 URL

Symfony 5 从控制台命令生成 URL

PHP
江户川乱折腾 2023-05-12 16:06:53
我是 Symfony 的新手,正在使用 5.x。我已经使用 Symfony\Component\Console\Command\Command 创建了一个控制台命令,并且正在尝试使用 Symfony\Component\HttpClient\HttpClient 来 POST 到一个 URL。我需要生成在同一台机器上运行的路由的 URL(但将来这可能会更改为不同的机器),因此主机可能类似于 localhost 或 example.com,并且 API 的端口是自定义的。我在网上搜索过,但我得到的唯一可能的解决方案是使用 Symfony\Component\Routing\Generator\UrlGeneratorInterface,并且网上充斥着旧版本 Symfony 的代码示例,我还没有设法得到这个工作。我最近的尝试是:public function __construct(UrlGeneratorInterface $router){    parent::__construct();    $this->router = $router;}但我真的不明白如何将参数 UrlGeneratorInterface $router 注入构造函数。我收到未提供参数的错误。我是否必须在其他地方创建 UrlGenerator 的实例并将其注入此处,或者是否有更简单的方法从命令中生成 Symfony 中的绝对 URL?我还不太了解容器。$url = $context->generate('view', ['Param' => $message['Param']], UrlGeneratorInterface::ABSOLUTE_URL);服务.yaml:App\Command\MyCommand:    arguments: ['@router.default']是否有更简单的方法通过显式指定主机、协议、端口、路由、参数等从控制台命令生成 URL?为什么 UrlGeneratorInterface 或 RouterInterface 不自动装配?如果我还启用了自动装配,是否需要在 services.yaml 中手动指定接线为 $router.default ?我知道执行函数的实现可能不正确,但如果不先让构造函数工作,我就无法修复它。这仍在进行中。
查看完整描述

3 回答

?
慕田峪4524236

TA贡献1875条经验 获得超5个赞

private $router您似乎遇到的问题不是由于您的服务声明,而是您缺少中变量的声明MyCommand。

因此,您可以保留services.yaml要点中显示的内容,无需更改自动装配变量,也不必手动声明命令

此外,您不需要$context从路由器中获取,您也可以在您的 中设置基本 URLframework.yaml,在这里您可以找到我找到它的位置。

请注意,我从执行中删除了一些代码,这是因为我无法访问您的其他文件。你可以重新添加这个。


查看完整回答
反对 回复 2023-05-12
?
慕斯709654

TA贡献1840条经验 获得超5个赞

好吧,解决这个问题并不是那么简单。许多文档已过时或未完全解决此问题。这是我到目前为止得到的:


服务.yaml:


Symfony\Component\Routing\RouterInterface:

    arguments: ['@router']

应用程序.php:


#!/usr/bin/env php

<?php

// application.php


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

require __DIR__.'/src/Kernel.php';


use Symfony\Bundle\FrameworkBundle\Console\Application;

use Symfony\Component\Routing\RouterInterface;

use Symfony\Component\Dotenv\Dotenv;


$dotenv = new Dotenv();

$dotenv->load(__DIR__.'/.env', __DIR__.'/.env.local');


$kernel = new App\Kernel(getenv('APP_ENV'), getenv('APP_DEBUG'));

$kernel->boot();


$container = $kernel->getContainer();


$application = new Application($kernel);


$application->add(new App\Command\MyCommand($container->get('router')));


$application->run();

注意:我将应用程序导入更改为 Symfony\Bundle\FrameworkBundle\Console\Application


我的命令.php:


<?php

// src/Command/MyCommand.php

namespace App\Command;


use Symfony\Component\Console\Command\Command;

use Symfony\Component\Console\Command\LockableTrait;

use Symfony\Component\Console\Input\InputInterface;

use Symfony\Component\Console\Output\OutputInterface;

use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

use Symfony\Component\Routing\RouterInterface;

use Symfony\Component\HttpClient\HttpClient;

use App\SQSHelper;


class MyCommand extends Command

{

    use LockableTrait;


    // the name of the command (the part after "bin/console")

    protected static $defaultName = 'app:my-command';


    protected $router;


    public function __construct(RouterInterface $router)

    {

        parent::__construct();

        $this->router = $router;

    }


    protected function configure()

    {

    }


    protected function execute(InputInterface $input, OutputInterface $output)

    {

        if($this->lock()) { // Prevent running more than one instance

            $endpoint = 

            $queueName = 'Queue';

            $queue = new SQSHelper();


            while($queue->getApproxNumberOfMessages($queueName)) {

                $message = $queue->receiveMessage($queueName);

                if($message) {

                    if($message['__EOQ__'] ?? FALSE) // End-of-Queue marker received

                        break;


                    $context = $this->router->getContext();

                    $context->setHost('localhost');

                    $context->setHttpPort('49100');

                    $context->setHttpsPort('49100');

                    $context->setScheme('https');

                    $context->setBaseUrl('');


                    $url = $this->router->generate('ep', ['MessageId' => $message['MessageId']], UrlGeneratorInterface::ABSOLUTE_URL);


                    $client = HttpClient::create();

                    $response = $client->request('POST', $url, [

                        'headers' => ['Content-Type' => 'application/json'],

                        'body' => $message['Body'] // Already JSON encoded

                    ]);

                }

            }


            $this->release(); // Release lock


            // this method must return an integer number with the "exit status code"

            // of the command. You can also use these constants to make code more readable


            // return this if there was no problem running the command

            // (it's equivalent to returning int(0))

            return Command::SUCCESS;


            // or return this if some error happened during the execution

            // (it's equivalent to returning int(1))

            // return Command::FAILURE;

        }

    }

}

如果有什么感觉不对,或者如果您可以提供更好的解决方案或改进,请贡献...


查看完整回答
反对 回复 2023-05-12
?
忽然笑

TA贡献1806条经验 获得超5个赞

Symfony 5.1 引入的解决方案:


https://symfony.com/doc/current/routing.html#generating-urls-in-commands


在命令中生成 URL 与在服务中生成 URL 的工作方式相同。唯一的区别是命令不在 HTTP 上下文中执行。因此,如果您生成绝对 URL,您将获得 http://localhost/ 作为主机名,而不是您的真实主机名。


解决方案是配置 default_uri 选项来定义命令在生成 URL 时使用的“请求上下文”:


# config/packages/routing.yaml

framework:

    router:

        # ...

        default_uri: 'https://example.org/my/path/'


查看完整回答
反对 回复 2023-05-12
  • 3 回答
  • 0 关注
  • 165 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信