Хуки validate, submit не работают вместе с #action формы

Главные вкладки

Аватар пользователя bora-89@drupal.org bora-89@drupal.org 17 января 2010 в 3:57

Всем привет!

Все предельно просто. Нужно иметь возможность хотя бы проверки данных, веденных пользователем в форму.
Приведу пример.
Есть форма:
$form['#action'] = = 'https://secure....';
$form['some_edit'] = array(
'#type' => 'textfield',
'#title' => t('Subject'),
'#default_value' => 'Text',
'#size' => 60,
'#maxlength' => 128,
'#required' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
'#validate' => array('the_function_that_needed_to_call'),
);
Так вот, чтобы хук валидации(сабмита) вызвался я так и не добился. Хотя без указанного св-ва #action все работает замечательно.
Но без #action поставленную задачу никак не решить.
Может кто нибудь из опытных объяснит в чем здесь ошибка?
Почему существует такое "разделение", в работы с #action?
Читал здесь http://drupal.org/node/282557
Читал здесь http://www.drupaler.co.uk/blog/validating-submitting-forms-other-website...
Полследняя ссылка вроде как и решает проблему, но в этой задаче, требуется одновременная передача данных постом и редирект на страницу
указанную в #action. Т.е точно так, как это делает обычная html форма.
Пожалуйса, дайте мне знать, что вы думаете по этому поводу.

Комментарии

Аватар пользователя Demimurych Demimurych 17 января 2010 в 22:08

Перечитал несколько раз но так и не понял проблемы.

Если у Вас стоит задача отправить данные формы в другой источник, то вернее это было бы делать, на мой взгляд следующим образом

пройти типичный для друпала цикл обработки формы на текущем сайте, в хуке _submit используя например RPC отправить данные на другой.

Аватар пользователя bora-89@drupal.org bora-89@drupal.org 18 января 2010 в 15:48

ОК. Опишу поподробнее.

Определяем простую форму
:
function my_custom_form() {
// Простой эдит на форме
$form['edit'] = array(
'#type' => 'textfield',
'#title' => t('Subject'),
'#required' => TRUE,
);
// Простой сабмит на форме
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
// Адрес, куда отправляем параметры формы
$form[#action] = 'https://secure....';
return $form;
}

// Функция валидации введенных данных на форме
function my_custom_form_validate($form, &$form_state) {
if($form_state['values']['edit'] == 'Чему-нибудь') {
form_set_error.....// генерируем ошибку
}
}
Теперь самое главное. Если я не описываю свойство #action, то ф - я валидации вызывается корректно. Но стоит его включить и она не вызывается, и происходит отправка данных на сервер(с переходом) без каких либо проверок. В чем пробелема ума не прилажу. Несколько абсурдная ситуация.

Обобщаю: Требуется передать параметры формы POST-запросом с "содержащимся" в нем редиректом, т.е так, как это делает обычная html форма с атрибутом action.
Что скажете?

Аватар пользователя Dan Dan 18 января 2010 в 16:09

Используйте редирект в сабмите, а не в форме (т.к. Вы задаёте другой обработчик):

<?php
function ХХХХХХ_form_submit($form_id, &$form_state) {
// ............
$form_state['redirect'] = 'node/123';
}
?>
Если форма будет перестраиваться (POST будет чист), попробуйте добавить $form_state['rebuild'] = false; и/или добавить фиктифный параметр для хранения в форме: $form_state['storage']['dummy'] = true;

Аватар пользователя bora-89@drupal.org bora-89@drupal.org 18 января 2010 в 18:16

RxB, да все верно. В самом первом сообщении я указывал вторую ссылку решающую почти такую задачу. С одним "но".

<?php
function my_module_newsletter_form_submit($form, &$form_state) {
// Удаленный урл, куда мы хотим отправить
$url = 'https://www.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8';
// set our headers
$headers = array(
'Content-Type' => 'application/x-www-form-urlencoded',
);
// отправление данных
$response = drupal_http_request($url, $headers, 'POST', http_build_query($form_state['values'], '', '&'));

// если все хорошо...
if ($response->code == 200) {
drupal_set_message(t('Thank you for subscribing to our newsletter.'));
// Или генерируем косяк
} else {
drupal_set_message(t('There was a problem with your submission. Please try again later.'), 'error');
}
}
?>

Все параметры корректно отправляются на сервер, но нужен редирект на ту страницу вместе с отправляемыми данными. Здесь мы только получаем ответ от сервера.

Dan, спасибо за помощь, но думаю что так не пройдет.

Какие еще могут быть варианты?

Аватар пользователя Виктор Степаньков ака RxB Виктор Степаньк... 18 января 2010 в 18:30

Ну так и установите в submit, в конце, после того как отправили данные постом:
В массив $data данные, если нужно их включить в GET
<?php$form_state['redirect'] = array('http://secret-site.com/script.cgi', $data);?>

Аватар пользователя penexe penexe 18 января 2010 в 18:51

что если проверять перед рендером формы, значение form_state, если форма сабмиченая, то менять action + рисовать hidden поля, написать please wait.. и js-сом засабмитеть 2й раз ?

Аватар пользователя Dan Dan 19 января 2010 в 1:13

"<a href="mailto:bora-89@drupal.org">bora-89@drupal.org</a>" wrote:
Dan, спасибо за помощь, но думаю что так не пройдет.

Я описал решение, которое у меня работало. Возможно я не понял проблему. У меня была задача - надо было при отправке формы перейти на другую страницу и поймать там POST формы. Вышеприведённый код это делал.

Аватар пользователя serious.vip@drupal.org serious.vip@dru... 19 января 2010 в 2:43

если речь идет о простой валидации данных перед отправкой их на удаленный сервер посредством браузера, как то:
-- ввел данные
-- нажал кнопку
-- данные провалидировались
-- ушел с данными на сайт

такая система работать не будет идеологически, потому как POST вы можете послать ТОЛЬКО из браузера (в ДАННОМ вашем желании), где данные легко могут поменять и после валидации, что сводит всю замороку с ней к нулю, то есть вы пытаетесь сделать систему, которая спросит сервер "все в порядке?", и после ответа "все в порядке" будет вольна делать что хочет. небольшая промашка в архитектуре. в данном случает drupal_http_requiest как раз-таки полностью решает задачу, потому как модифицировать запрос невозможно. как вариант - написать обертку для http_requiest и не перенаправлять на сайта, а эмулировать все это, но это такая морока...

Аватар пользователя bora-89@drupal.org bora-89@drupal.org 20 января 2010 в 0:45

Ух, всем спасибо за помощь.

Немного расскажу о чем вообще это все. Пишется платежный модуль(точнее уже написан). Для оплаты товаров карточками VISA и MasterCart.
Есть html-форма примерно след содержания:

...

Вот эти инпуты, это отправляемые параметры на удаленный сервер "https://secure.webpay.by". И сразу же редирект на форму оплаты.
На самом деле сами параметры проверять нет смысла, они генерируются кодом, это не ручной ввод.
Весь сыр бор из-за того, что я хотел объединить пользовательское соглашение (несколько параметров формы) с формой оплаты. Как раз параметры соглашения и нужно было проверять на валидность. Сейчас это просто на разных страницах.

Аватар пользователя sg85 sg85 21 ноября 2013 в 21:45

"Goodboy" wrote:
в итоге, получилось запустить validate с #action на удаленный сервер?

это технически не возможно, тут редирект, либо валидация через JS, либо валидация на том ресурсе, куда Вы отдали форму.

Аватар пользователя goodboy goodboy 22 ноября 2013 в 11:19

sg85, я поступил так, как в этом топике посоветовал penexe. Да, немного некрасиво, что форма дважды грузится, но валидация выполняется.

Аватар пользователя tastysoop tastysoop 22 ноября 2013 в 14:44

Чтобы форма дважды не грузилась, нужно делать ajax сабмит формы на свой сайт, а при успешном сабмите возвращать код, меняющий action формы на нужный и делающий нормальный сабмит на внешний сайт.