Как Symfony2 передает параметр URI в метод действия контроллера?

Я начал изучать 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 () возвращает массив аргументов для передачи в метод действия. Но если бы контроллер был:

// 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.

Я надеюсь, что этот вопрос понятен, если нет, пожалуйста, скажите мне, и я сделаю правку.

Спасибо за внимание!

1

Решение

Все это делается в контроллере Resolver HttpKernel / Controller / ControllerResolver.php с помощью getArguments() & doArguments(),

Для лучшего понимания вы найдете то, что вам нужно в Получение Аргументов Контроллера


Редактировать: Ответить на комментарий.

Использует ли 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());
}
4

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

  1. Запрос обрабатывается фронт-контроллером Symfony (например, app.php);
  2. Ядро Symfony (то есть ядро) просит маршрутизатор проверить запрос;
  3. Маршрутизатор сопоставляет входящий URL-адрес с конкретным маршрутом и возвращает информацию о маршруте, включая контроллер, который должен быть выполнен;
  4. Ядро Symfony выполняет контроллер, который в конечном итоге возвращает объект Response.

введите описание изображения здесь

Ресурс

1

В вашем примере у вас есть только один параметр в вашем действии, поэтому для нас очевидно, что его необходимо заполнить с маршрута.

Чтобы расширить ваш пример, если вы добавили еще один параметр в маршрут, например:

# 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 может просматривать имена ваших аргументов и сопоставлять их с параметрами маршрута. Это также означает, что вы можете иметь indexAction аргументы в любом порядке, если их имена соответствуют параметрам маршрута. Я полагаю, что Symfony внутренне использует API Reflection, чтобы понять все это.

1