Вызов формы, Drupal FAPI

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

Аватар пользователя bratello bratello 16 января 2011 в 22:24

К сожалению многие программеры Друпал практикуют изменение и вставку данных в ДБ только в обработчиках формы, не выводя функционал данных в отдельные классы или функции. Возникла необходимость делать изменения данных, причем в итерации. Для этих целей я использую drupal_execute($form_id, $form_state). Например форма принимает параметры p1 & p2:

<?php
$form_state 
= array('p1' => 10'p2' = array(truefalse));
drupal_execute($form_id$form_state);
?>

и кажется все работает, правда предварительно пришлось включить необходимый admin.inc файл, потому что форма сама была имплементирована в админ файле, и все это мероприятие нужно для автоматизации администрирования. Задача развивается дальше, часть данных, которые передаются в $form_state берутся из csv файла, который предварительно аплоадится. Для этих целей я изобрел небольшую библиотеку классов, которой конфигурируется формат $form_state (имя поля, тип), библиотека принимает массив данных из csv (либо из массива), проводит валидацию этих данных, и для остальных полей необходимой формы предлагает ввести их пользователю вручную. Для этих целей библиотека классов умеет создавать самую примитивную форму. Таким образом, параметр p1 загружается из csv (например 30 значений поля p1), а поле p2 довводится пользователем, далее строится массив из 30-ти элементов, где каждым елементом массив является один конкретный form_state:

<?php
$form_state_array 
= array(
array(
'p1' => $csv_val0'p2' => $user_defined_p2),
array(
'p1' => $csv_val1'p2' => $user_defined_p2),
array(
'p1' => $csv_val2'p2' => $user_defined_p2),
...
...
array(
'p1' => $csv_val29'p2' => $user_defined_p2)
);
?>

И каждый элемент массива передаётся в итерации в drupal_execute. Так в кратции это работает.

Но форма доввода данных получается очень не интуитивная, значительно удобнее было бы использовать оригинальную форму в паре с уже существующим импортом из csv. Идея в том чтобы после загрузки данных из csv подгружать оригинальную форму, предварительно убрав поля, которые были загружены из csv, и все это на сабмите merge друг с другом и в итерации передать в drupal_execute. Пользуем для этих целей drupal_get_form & form_alter, но теперь нужно избежать form_id_submit() & form_id_validate(), вместо этого принять все данные в моих обработчиках, и дальше по сценарию итерация. Видимо нужно модифицировать $form['#submit'] и $form['#validate'] массивы в form_alter хуке, но есть сомнения что правильно пройдет form rebuild и что будут работать ahah колбеки оригинальной формы.

Если кто то сталкивался с такими нетривиальными задачками - порекомендуйте как быть.

Комментарии

Аватар пользователя bratello bratello 17 января 2011 в 13:58

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

Немного упрощу вопрос. Есть форма, ее нужно вызвать много раз, часть данных получаем из csv, часть из полей самой формы, которая вызывается как бы в дизайн моде. Дальше это все сливается и передаётся в drupal_execute много раз. Если я как то мутно объясняюсь - спрашивайте.

Аватар пользователя bratello bratello 17 января 2011 в 14:49

"RxB" wrote:
Multistep штоле получится?

Ты сейчас про Chaos говоришь или про то что мне нужно? Ну если учитывать что сначала нужно аплоадить csv файл, а потом вводить данные с формы то наверное мультистеп. А про Chaos ф так толком и не понял, есть типа какой то инструмент для построения визардов, но как он мне может тут помочь я не знаю. Может просветишь?

Аватар пользователя bratello bratello 17 января 2011 в 19:35

Принцип такой. Есть форма, для простоты форма регистрации пользователей. Это только для примера, конкретный случай значительно сложнее, включая AHAH и множество альтераций формы из других модулей!

Допустим программер написал эту форму не очень умело, и он не знал что есть user_save - ее в системе вообще не существует, а прямо в обработчике add_user_form_submit написал SQL INSERT. Для того чтобы администратор сайта вставил к примеру 100 пользователей нужно часто и быстро кликать и клацать по клавиатуре, например администратор сайта получил список e-mail из какого нибудь старого своего сайта, который был сделан не на друпале даже. И такая история у администратора сайта будет повторяться регулярно, откуда он берет эти данные это его проблема, вот такой он способный малый. Для этих целей логично было бы написать модуль, который будет принимать эти данные из текстового файла и запихивать в систему. Так как разработчик у нас умелый то нужно будет вызывать drupal_execute('add_user_form', $params) для каждой записи в текстовом файле. Можно было бы конечно скопировать код обработчика add_user_form_submit к себе в модуль, но с каждым апдейтом есть риск попасть в интересную ситуацию, это не наш путь. Ситуация еще усложняется тем, что в файле есть только почтовые адреса будущих пользователей сайта, а дополнительные параметры для add_user_form как то статус, роль, которую нужно присвоить вновь созданному пользователю, все те параметры которые администратор обычно выставляет на add_user_form для каждого отдельного пользователя, нужно выставить одноразово для всех записей в текстовом файле. В случае импорта все эти параметры администратор должен решать на момент импорта данных из текстового файла, вот всем пользователям из этого файла присваевается роль читатели, а из следующего файла - писатели. Логично было бы на экране показать саму форму add_user_form, исключая поля, данные для которых были загружены из текстового файла на предыдущем этапе. Но форму нужно только показать, и минуя add_user_form_submit & add_user_form_validate принять данные у себя, построить из данных полученых их файла и формы массив и передать каждый элемент массива в drupal_execute('add_user_form'). В итоге мы несколькими нажатиями кнопок создали 100 новых пользователей на сайте.

Если чего то не понятно спрашивай, я попробую еще как нибудь обьяснить.

Аватар пользователя bratello bratello 17 января 2011 в 20:46

"RxB" wrote:
Всё равно половину не понял.

А какую половину понял? Проблематика ясна? Кликать клацать долго, текстовый файл со списком адресов? Или drupal_execute?

"RxB" wrote:
Batch API не подходит?

Это уже как исполнить, я смотрел этот API, он даёт хороший сервис, но сначала ему нужно рассказать что нужно сделать. Проблема же заключается в том что мы должны сначала получить то что исполнить, то что нужно исполнить находится в обработчике формы, данные частично находятся в текстовом файле, частично заполняются тем, кто будет все это запускать.

Другой пример - есть форма для рассылки спама! Поле для ввода почтового адреса, поля для сообщения, и поле для ввода сабджекта, кнопка Send. Есть сто почтовых адресов, нужно сто раз заполнить все три поля, почтовые адреса берутся из файла по порядку, сообщение и сабджект для всех одинаковое. Хочется это все автоматизировать:

  1. Загрузить на сервер csv файл со списком почтовых адресов
  2. Показать уже существующую форму рассылки спама, но без поля для ввода почтового адреса - адреса мы зугрузили из текстового файла
  3. Принять данные из формы - текст сообщения и сабжект
  4. Вызвать эту форму programmatically (drupal_execute) N раз, где каждый раз передавать следующий адрес из текстового файла, и введеные прежде текст сообщения и сабжект

Кажется вариант с $form['#submit'] и $form['#validate'] единственно верный способ, потому что после сабмита не плохо было бы показать пользователю страницу с общим отчетом о том что сейчас будет выполнено и сколько раз, с просьбой выполнить или отменить.