Symfony3에서 POST 값을 1 차원 배열로 만들고 싶습니다.

개요



Symfony3에서 POST 값의 루트 배열의 이름을 바꾸려면 FormFactory::createNamed()를 사용하십시오.
GitHub 공식 저장소 : htps : // 기주 b. 이 m/sym후니/후우rm/bぉb/3.4/후rm후우c와 ry. php

경위



EC-CUBE4의 플러그인 개발 중에 링크형 결제로 50개가 넘는 요청 파라미터를 결제대행사 측 서버에 POST한다는 장면을 만났다.

Symfony의 Controller에서 사용하는 createForm() 는 이용하는 FormType이 폼의 이름이 되고, 폼명의 세로 배열에 실제로 POST하는 값이 가로 배열로서 들어가는 2차원 배열이 된다.

HogeController.php

$form = $this->createForm(HogeType::class, $Hoge);

return ['form' => $form->createView()];


POST

array:1 [▼
  "hoge" => array:2 [▼    // ← このhogeっていう親の配列が邪魔!!
    "key" => "value"
    "_token" => "TOKEN"
  ]
]

이것은 데이터의 연결을 매핑하기 위한 것이라고 생각되지만, 이번과 같이 소정의 포맷에 따라 리퀘스트해야 할 때에 곤란하다.

템플릿 파일에 HTML을 직접 써 버리는 방법도 있지만, 이번 경우에는 요청 파라미터가 50을 넘고, 수주 상태에 따라서는 순차적으로 동적으로 출력해야 하는 파라미터도 있었기 때문에 어떻게든 FormType에서 대응하고 싶다.

hoge.twig

<input type="hidden" name="hoge" value={{ hoge }} />    // これでもいいのだが…
// 以下、最大で999項目(笑)
<input type="hidden" name="param1" value={{ value1 }} />
<input type="hidden" name="param2" value={{ value2 }} />
<input type="hidden" name="param3" value={{ value3 }} />
...

이 때문에, name 속성을 능숙하게 커스터마이즈 할 수 없는가와 여러가지 조사한 결과, FormFactory::createNamed() 에 도착했다.

사용법



첫번째 인수에 임의의 폼명 건네주어, createForm 와 같이 사용해 하면 된다.
$form = $formFactory->createNamed('form_name', HogeType::class, $Hoge, [
  'action' => 'https://example.com'    // 第四引数もcreateFormの第三引数と同様に使える。
]);

이번에는 부모의 배열이 방해이므로, 제1 인수에 공문자를 건네준다.

HogeController.php

$form = $this->formFactory->createNamed('', HogeType::class, $Hoge);
return ['form' => $form->createView()];

POST

array:2 [▼
  "key" => "value"
  "_token" => "TOKEN"
]

구현 읽기



모처럼이므로 구현을 읽어 보았다.
상속 관계를 따라 가면,

항상 사용하는 createForm()



HogeController → (상속) -> Controller → (Trait) -> ControllerTrait::createForm ()

Symfony/Bundle/FrameworkBundle/Controller/Controller.php
Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php

ControllerTrait.php
protected function createForm($type, $data = null, array $options = [])
{
    return $this->container->get('form.factory')->create($type, $data, $options);
}

이대로 쫓으면 ...

FormFactory.php

public function create($type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = [])
{
    return $this->createBuilder($type, $data, $options)->getForm();
}

public function createBuilder($type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = [])
{
    if (!\is_string($type)) {
        throw new UnexpectedTypeException($type, 'string');
    }

    return $this->createNamedBuilder($this->registry->getType($type)->getBlockPrefix(), $type, $data, $options);
}

실은 이번에 사용한 createNamed() 가 랩 하고 있다 createNamedBuilder() 를 한층 더 랩 하고 있을 뿐이었다!

한편, 이번에 사용한 createNamed()



HogeController → (상속) → Controller → (DI?) → FormFactory::createNamed()

Symfony/Bundle/FrameworkBundle/Controller/Controllerphp
Symfony/Component/Form/FormFactory.php

FormFactory.php
public function createNamed($name, $type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = [])
{
    return $this->createNamedBuilder($name, $type, $data, $options)->getForm();
}


public function createNamedBuilder($name, $type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = [])
{
    if (null !== $data && !\array_key_exists('data', $options)) {
        $options['data'] = $data;
    }

    if (!\is_string($type)) {
        throw new UnexpectedTypeException($type, 'string');
    }

    $type = $this->registry->getType($type);

    $builder = $type->createBuilder($this, $name, $options);

    // Explicitly call buildForm() in order to be able to override either
    // createBuilder() or buildForm() in the resolved form type
    $type->buildForm($builder, $builder->getOptions());

    return $builder;
}


글쎄, 깔끔한

후기



이렇게 구현을 읽을 수 있어, Core 부분으로부터 유연하게 희망의 구현을 실현한다고 하는 테크닉도 필요하다고 생각했다.
Symfony의 DI가 어떤 구조로 움직이고 있는지 모르기 때문에, 그 근처의 구현에 다가가 보는 것도 있을지도 궁금합니다.

지적이라든지 더 좋은 방법이 있으면 지적 부탁드립니다! !

홍보



EC-CUBE, Laravel의 개발 맡겨주세요! !

좋은 웹페이지 즐겨찾기