繁体   English   中英

Symfony2如何将URI的参数传递给控制器​​的Action方法?

[英]How does Symfony2 passes the parameter of a URI to the controller Action method?

我已经开始学习Symfony2。 我遇到一个疑问:如果我有这条路线:

# app/config/routing.yml
hello:
    path:      /hello/{name}
    defaults:  { _controller: AcmeHelloBundle:Hello:index }

而这个控制器:

// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
class HelloController
{
    public function indexAction($name)
    {
        return new Response('<html><body>Ciao '.$name.'!</body></html>');
    }
}

在内部Symfony2(在app / bootstrap.php.cache内部)调用PHP内置函数user_func_array()。

$arguments = $this->resolver->getArguments($request, $controller);
$response = call_user_func_array($controller, $arguments);

调用getArguments()方法将返回一个参数数组,以传递给action方法。 但是,如果控制器是:

// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
class HelloController
{
    public function indexAction($n)
    {
        return new Response('<html><body>Ciao '.$n.'!</body></html>');
    }
}

Symfony会抱怨RuntimeException,因为未设置参数$ n。

我的问题是:Symfony如何控制此行为,我的意思是,如果路由具有{name}参数,为什么控制器必须具有带有$ name参数的操作方法,并且该参数必须称为$ name?

在普通的PHP中,这会起作用:

$name = 'Alex';
function indexAction($n) {
   echo $n;
}
$f = 'indexAction';
$arguments = array($name);
call_user_func_array($f, $arguments);

即使函数签名接受名为$ n而不是$ name的参数。

我希望这个问题是可以理解的,如果不能,请告诉我,我将进行编辑。

感谢您的关注!

这些都通过getArguments()doArguments()在Controller Resolver HttpKernel / Controller / ControllerResolver.php中 getArguments()

为了更好地理解,您将在“ 获取控制器参数”中找到所需的内容。


编辑:回答评论。

Symfony是否在内部使用ReflectionParameter类来跟踪方法签名的参数并将它们与路由参数匹配?

是的,ControllerResolver使用:

方法如下:

 public function getArguments(Request $request, $controller)
    {
        if (is_array($controller)) {
            $r = new \ReflectionMethod($controller[0], $controller[1]);
        } elseif (is_object($controller) && !$controller instanceof \Closure) {
            $r = new \ReflectionObject($controller);
            $r = $r->getMethod('__invoke');
        } else {
            $r = new \ReflectionFunction($controller);
        }
        return $this->doGetArguments($request, $controller, $r->getParameters());
    }
  1. 该请求由Symfony前端控制器(例如app.php)处理;
  2. Symfony核心(即内核)要求路由器检查该请求。
  3. 路由器将输入的URL与特定路由匹配,并返回有关路由的信息,包括应执行的控制器;
  4. Symfony内核执行控制器,最终返回一个Response对象。

在此处输入图片说明

资源资源

在您的示例中,您的操作上只有一个参数,因此对于我们来说很明显,需要从路径中填充该参数。

为了扩展您的示例,如果您向路由添加了另一个参数,例如:

# app/config/routing.yml
hello:
    path:      /hello/{name}/{surname}
    defaults:  { _controller: AcmeHelloBundle:Hello:index }

并将您的控制器更改为:

// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
class HelloController
{
    public function indexAction($s, $n)
    {
        return new Response('<html><body>Ciao '.$n.' '.$s.'!</body></html>');
    }
}

Symfony不知道用哪个路由参数填充哪个变量$s$n

如果您更改操作:

    public function indexAction($surname, $name)
    {
        return new Response('<html><body>Ciao '.$name.' '.$surname.'!</body></html>');
    }

现在,Symfony可以查看您的参数名称并将其映射到route参数。 这也意味着您可以以任意顺序使用indexAction参数,只要它们的名称与route参数匹配即可。 我相信Symfony内部使用了Reflection API来解决所有这些问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM