Я работаю с некоторыми формами Symfony, и мне нужно получить доступ к изначально отправленным (нетронутым) данным. Все методы доступа к данным $form->getData(), $form->getViewData() и $form->getModelData() дают мне уже преобразованные значения, но мне нужны данные, как в событии PRE_SUBMIT.
Я мог бы написать слушателя и извлечь их на PRE_SUBMIT, но тогда мне придется хранить эту информацию где угодно и обращаться к ней в моем сервисе, работая с формой. На данный момент моя служба видит только переданный объект формы и выполняет свою работу без каких-либо других зависимостей.
Другие обходные пути включают чтение из объекта запроса. Не выглядит разумным вариантом, потому что форма может быть заполнена из других источников (например, сеанс, это форма фильтра).
Есть ли «официальный» способ доступа к изначально отправленным данным непосредственно из объекта формы? Если нет, стоит ли запрашивать функцию? Есть какие-нибудь мнения по этому поводу?
(Мой вариант использования - это форма фильтра, где состояние сохраняется и извлекается из сеанса. Поскольку форма может быть отправлена без данных, поступающих из запроса, включающего режимы для HTML-POST, HTML-GET и JSON-POST, я не не хочу просто хранить данные запроса.)
Изменить 2018-06-07: в соответствии с просьбой в комментариях я привожу пример кода:
/**
* handles the filterForm request reading POST-data or namespaced JSON payload with POST method or any standard form request
*
* @param FormInterface $filterForm
* @return void
* @throws ResponseException
*/
public function handleRequest(FormInterface $filterForm): void
{
// reset the filter state in the session, if a reset_filter query parameter was set
if (true === $this->request->query->getBoolean('reset_filter', false)) {
$this->setFilterState(null, $this->request->attributes->get('_route'));
$this->filterIsActive = true;
}
// handle filter submission in json context
if ($this->request->isMethod('POST') && $this->request->attributes->get('_format') === 'json') {
if ($this->request->get($filterForm->getName())) {
$submitData = $this->request->get($filterForm->getName());
}
else {
$postData = JsonHelper::parseAndCheckJsonPostData($this->request);
if ($postData instanceof Response) {
throw new ResponseException($postData);
}
$submitData = $postData[$filterForm->getName()] ?? null;
}
if (null !== $submitData) {
dump($submitData);
$filterForm->submit($submitData, true);
dump($filterForm->getData());
}
}
else {
// @todo find a smooth way to get the original submitted data of a form, when it is handled by the default handleRequest()-menthod
$submitData = null;
$filterForm->handleRequest($this->request);
}
// load the filter state from the session and submit it, if it is not yet set and we are in HTML context
if (!$filterForm->isSubmitted()
&& $this->request->attributes->get('_format') === 'html'
&& null !== $this->getFilterState($this->request->attributes->get('_route'))
) {
$filterForm->submit($this->getFilterState($this->request->attributes->get('_route')));
}
if ($filterForm->isSubmitted()) {
$this->filterIsActive = true;
// return an JSON error-document, if the filter form is not valid
if (!$filterForm->isValid() && $this->request->attributes->get('_format') === 'json') {
throw new ResponseException(
new JsonResponse([
'type' => 'error',
'message' => $this->translator->trans('Form.Filter.errorMessage'),
'filterForm' => $this->serializer->normalize($filterForm->createView()),
], Response::HTTP_BAD_REQUEST)
);
}
// store the new filter state, if filter is active and and valid
if ($filterForm->isValid() && null !== $submitData) {
$this->setFilterState($submitData, $this->request->attributes->get('_route'));
}
}
}
Выводит это:
array:4 [▼
"singleEntity" => "1"
"multipleEntities" => array:1 [▼
0 => "1"
]
"dateRange" => array:2 [▼
"left_date" => "06.06.2018"
"right_date" => "07.06.2018"
]
"submit" => true
]
array:11 [▼
"singleEntity" => MySingleEntity {#3739 ▶}
"facilities" => ArrayCollection {#3419 ▼
-elements: array:1 [▼
0 => MyMultiEntity {#3799 ▶}
]
}
"createdOrUpdatedBetween" => array:2 [▼
"left_date" => DateTime @1528236000 {#3408 ▼
date: 2018-06-06 00:00:00.0 Europe/Berlin (+02:00)
}
"right_date" => DateTime @1528322400 {#3397 ▼
date: 2018-06-07 00:00:00.0 Europe/Berlin (+02:00)
}
]
]
Формы используют LexikFormFilterBundle, где как минимум поля Date и DateTime преобразуются в DateTime-объекты. В моем случае я часто использую Entity-фильтры, и их представленные значения преобразуются в их сущности. Это здорово, так как это очень помогает в обработке логики фильтра.
Можете ли вы предоставить пример использования данных, которые поступают из запроса (и вам нужны в необработанном формате), и во что они преобразуются? Кроме того, для чего вам нужны необработанные данные? (Просто спросите, может быть, есть лучший подход, чем пытаться получить необработанные данные из формы)
Я не хотел обсуждать свою реализацию, но теперь вы спросили, я предоставил свой код. Как видите, я сохраняю отправленные данные в сеансе и загружаю (и отправляю) их снова, когда пользователь в следующий раз загрузит html-версию страницы. Поэтому, когда пользователи возвращаются, у них есть последнее состояние фильтра. На данный момент рассматриваемый случай не реализуется на практике (фильтры применяются только через POST / JSON), но, возможно, это вызовет проблему в будущем. Итак, я ищу окончательное решение без взлома.




У меня есть два варианта сохранения отправленных данных
1) Возьмите прямо из запроса
$submitted_data = [];
foreach ($form->all() as $child) {
if ($request->request->has($child->getName())) {
$submitted_data[$child->getName()] = $request->request->get($child->getName());
}
}
2) используйте события формы
$submitted_data = null;
$formBuilder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use (&$submitted_data) {
$submitted_data = $event->getData();
});
Оба варианта и почему они не являются хорошими вариантами обсуждаются внутри вопроса. В основном вопрос заключается в получении необработанных данных из объекта формы, который передается методу handleRequest, который не должен иметь никаких других зависимостей. Я мог бы сделать PRE_SUBMIT-материал и сохранить необработанные данные для запроса, если они не исходят оттуда. Таким образом, метод handleRequest всегда получает необработанные данные формы из запроса, даже если форма была заполнена из пользовательского сеанса. Немного хакерский, но может быть решением.
Если это форма фильтра, зачем вам преобразовывать значения? Не могли бы вы объяснить случай поподробнее? Обычно в форме фильтра значения не преобразуются.