如何从 Early/Auto 加载的 Symfony 3 路由器生成绝对 URL
How to generate Absolute URL from Early/Auto loaded Symfony 3 router
我正在编写 Guards 来处理我的 Symfony 3 应用程序的 OAuth。
作为其中的一部分,在我的一项服务中,我需要生成一个绝对 URL 作为回调 URL 发送到 Twitter。
#services.yml
...
app.twitter_client:
class: MyApiBundle\Services\TwitterClient
arguments:
- %twitter_client_id%
- %twitter_client_secret%
- connect_twitter_check
- '@request_stack'
- '@router'
- '@logger'
app.twitter_authenticator:
class: MyApiBundle\Security\TwitterAuthenticator
arguments:
- '@app.twitter_client'
- '@logger'
记录器是临时调试用的。
#TwitterClient.php service
...
use Monolog\Logger;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RouterInterface;
class TwitterClient
{
/**
* TwitterClient constructor.
* @param string $identifier
* @param string $secret
* @param string $callbackUrl
* @param RequestStack $requestStack
* @param RouterInterface $router
* @param Logger $logger
*/
public function __construct(
string $identifier,
string $secret,
string $callbackUrl,
RequestStack $requestStack,
RouterInterface $router,
Logger $logger
) {
$callbackUrl = $router->generate($callbackUrl, [], RouterInterface::ABSOLUTE_URL);
$logger->info($callbackUrl);
...
}
当它向日志输出 $callbackUrl
时,它只是说本地主机,即使我正在使用不同的 URL.
访问它
http://localhost/connect/twitter/check
但是如果我从我的控制器上做同样的事情,它会输出完整的 URL。
#TwitterController.php
...
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;
class TwitterController extends Controller
{
/**
* @Route("/connect/twitter")
* @return RedirectResponse
*/
public function connectAction()
{
/** @var RouterInterface $router */
$router = $this->container->get('router');
$callbackUrl = $router->generate('connect_twitter_check', [], RouterInterface::ABSOLUTE_URL);
/** @var Logger $logger */
$logger = $this->container->get('logger');
$this->container->get('logger')
->info($callbackUrl);
...
这输出:
https://dev.myapi.com:8082/app_dev.php/connect/twitter/check
dev.myapi.com
域在我的主机文件中设置并指向本地主机,以便更容易区分我的本地应用程序,也更容易与 OAuth 服务集成。
我设法通过设置路由器上下文解决了这个问题。
我已经加载了 RequestStack 来访问用户的 IP,所以我用它来设置路由的上下文,然后路由器按预期工作。
我 运行 进入 problems 试图在构造函数中使用 RequestStack,所以我最终重构了它,以便它尽可能晚地使用 RequestStack。
class TwitterClient
{
private $identifier;
private $secret;
private $callbackUrl;
private $requestStack;
private $router;
private $server;
/**
* TwitterClient constructor.
*
* @param string $identifier
* @param string $secret
* @param string $callbackUrl
* @param RequestStack $requestStack
* @param RouterInterface $router
*/
public function __construct(
string $identifier,
string $secret,
string $callbackUrl,
RequestStack $requestStack,
RouterInterface $router
) {
$this->identifier = $identifier;
$this->secret = $secret;
$this->callbackUrl = $callbackUrl;
$this->requestStack = $requestStack;
$this->router = $router;
}
/**
* Wait until the last moment to create the Twitter object to make sure that the requestStack is loaded.
*
* @return \League\OAuth1\Client\Server\Twitter
*/
private function getServer()
{
if (!$this->server) {
$context = new RequestContext();
$context->fromRequest($this->requestStack->getCurrentRequest());
$this->router->setContext($context);
$callbackUrl = $this->router->generate($this->callbackUrl, [], RouterInterface::ABSOLUTE_URL);
$this->server = new Twitter(
[
'identifier' => $this->identifier,
'secret' => $this->secret,
'callback_uri' => $callbackUrl,
]
);
}
return $this->server;
}
...
}
我正在编写 Guards 来处理我的 Symfony 3 应用程序的 OAuth。
作为其中的一部分,在我的一项服务中,我需要生成一个绝对 URL 作为回调 URL 发送到 Twitter。
#services.yml
...
app.twitter_client:
class: MyApiBundle\Services\TwitterClient
arguments:
- %twitter_client_id%
- %twitter_client_secret%
- connect_twitter_check
- '@request_stack'
- '@router'
- '@logger'
app.twitter_authenticator:
class: MyApiBundle\Security\TwitterAuthenticator
arguments:
- '@app.twitter_client'
- '@logger'
记录器是临时调试用的。
#TwitterClient.php service
...
use Monolog\Logger;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RouterInterface;
class TwitterClient
{
/**
* TwitterClient constructor.
* @param string $identifier
* @param string $secret
* @param string $callbackUrl
* @param RequestStack $requestStack
* @param RouterInterface $router
* @param Logger $logger
*/
public function __construct(
string $identifier,
string $secret,
string $callbackUrl,
RequestStack $requestStack,
RouterInterface $router,
Logger $logger
) {
$callbackUrl = $router->generate($callbackUrl, [], RouterInterface::ABSOLUTE_URL);
$logger->info($callbackUrl);
...
}
当它向日志输出 $callbackUrl
时,它只是说本地主机,即使我正在使用不同的 URL.
http://localhost/connect/twitter/check
但是如果我从我的控制器上做同样的事情,它会输出完整的 URL。
#TwitterController.php
...
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;
class TwitterController extends Controller
{
/**
* @Route("/connect/twitter")
* @return RedirectResponse
*/
public function connectAction()
{
/** @var RouterInterface $router */
$router = $this->container->get('router');
$callbackUrl = $router->generate('connect_twitter_check', [], RouterInterface::ABSOLUTE_URL);
/** @var Logger $logger */
$logger = $this->container->get('logger');
$this->container->get('logger')
->info($callbackUrl);
...
这输出:
https://dev.myapi.com:8082/app_dev.php/connect/twitter/check
dev.myapi.com
域在我的主机文件中设置并指向本地主机,以便更容易区分我的本地应用程序,也更容易与 OAuth 服务集成。
我设法通过设置路由器上下文解决了这个问题。 我已经加载了 RequestStack 来访问用户的 IP,所以我用它来设置路由的上下文,然后路由器按预期工作。 我 运行 进入 problems 试图在构造函数中使用 RequestStack,所以我最终重构了它,以便它尽可能晚地使用 RequestStack。
class TwitterClient
{
private $identifier;
private $secret;
private $callbackUrl;
private $requestStack;
private $router;
private $server;
/**
* TwitterClient constructor.
*
* @param string $identifier
* @param string $secret
* @param string $callbackUrl
* @param RequestStack $requestStack
* @param RouterInterface $router
*/
public function __construct(
string $identifier,
string $secret,
string $callbackUrl,
RequestStack $requestStack,
RouterInterface $router
) {
$this->identifier = $identifier;
$this->secret = $secret;
$this->callbackUrl = $callbackUrl;
$this->requestStack = $requestStack;
$this->router = $router;
}
/**
* Wait until the last moment to create the Twitter object to make sure that the requestStack is loaded.
*
* @return \League\OAuth1\Client\Server\Twitter
*/
private function getServer()
{
if (!$this->server) {
$context = new RequestContext();
$context->fromRequest($this->requestStack->getCurrentRequest());
$this->router->setContext($context);
$callbackUrl = $this->router->generate($this->callbackUrl, [], RouterInterface::ABSOLUTE_URL);
$this->server = new Twitter(
[
'identifier' => $this->identifier,
'secret' => $this->secret,
'callback_uri' => $callbackUrl,
]
);
}
return $this->server;
}
...
}