Как лучше реализовать перехват события?

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

Аватар пользователя Serega_od Serega_od 24 сентября 2009 в 15:35

Всем привет!
Мне необходимо сделать следующее: Чтобы после отправки формы выполнялся некий скрипт PHP.
Подскажите пожалуйста как лучше перехватить событие, слышал что можно с помощью хуков или с помощью спец. модуля который выполняет определенное действие после указанного события(слышал о таком , но забыл как называется).

Заранее спасибо!

Комментарии

Аватар пользователя andriy.olischuk andriy.olischuk 24 сентября 2009 в 15:43

Смотря что за форма. Если в ноде - то hook_nodeapi, если в комментарии, то hook_comment.
Для перехвата, к примеру, создаёте свой небольшой модуль mymodule и в нём функцию mymodule_nodeapi().
Как внутри этого хука обрабатывать события - можно посмотреть в официальной доке или гугле.

Аватар пользователя Serega_od Serega_od 24 сентября 2009 в 15:44

"andriy.olischuk" wrote:
Смотря что за форма. Если в ноде - то hook_nodeapi, если в комментарии, то hook_comment.
Для перехвата, к примеру, создаёте свой небольшой модуль mymodule и в нём функцию mymodule_nodeapi().
Как внутри этого хука обрабатывать события - можно посмотреть в официальной доке или гугле.

Спасибо! Моя форма создана с помощью модуля WebForm.

Аватар пользователя andriy.olischuk andriy.olischuk 24 сентября 2009 в 16:02

WebForm создаёт ноду если мне не изменяет память, поэтому пробуйте через hook_nodeapi, можно с проверкой на тип ноды (чтобы в остальных местах не срабатывало).

Аватар пользователя VladoMire VladoMire 24 сентября 2009 в 17:14

А нужен ли перехват после отправки? Если это сами решили, то может Ваша задача решается проще.

В Webform имеется при создании анкеты(опросника), специальное поле Additional Processing, которое можно загрузить PHP код, после дополнительной валидации или без неё.
Может это и решит проблему без различных дополнительных манипуляций?

Аватар пользователя glu2006 glu2006 24 сентября 2009 в 17:29

VladoMire wrote:
А нужен ли перехват после отправки? Если это сами решили, то может Ваша задача решается проще.

В Webform имеется при создании анкеты(опросника), специальное поле Additional Processing, которое можно загрузить PHP код, после дополнительной валидации или без неё.
Может это и решит проблему без различных дополнительных манипуляций?

Зависит от того какую задачу хочет выполнить человек после отправки формы. Мы же об этом не знаем, поэтому и подходим к данному вопросу несколько иначе :). + хранить в БД php код не самое лучшее решение (конечно без этого часто не обойтись, но если есть возможность этого избежать, то лучше этого избегать). Болезнь проще предотвратить чем лечить.

Аватар пользователя Serega_od Serega_od 24 сентября 2009 в 17:17

"VladoMire" wrote:
А нужен ли перехват после отправки? Если это сами решили, то может Ваша задача решается проще.

В Webform имеется при создании анкеты(опросника), специальное поле Additional Processing, которое можно загрузить PHP код, после дополнительной валидации или без неё.
Может это и решит проблему без различных дополнительных манипуляций?


Спасибо! Т.е. Всё что мне нужно - создать поле Additional Processing и поместить туда PHP код и где-то в настройках указать чтоб оно срабатывало при отправке формы?

Аватар пользователя Serega_od Serega_od 24 сентября 2009 в 17:31

"glu2006" wrote:
Зависит от того какую задачу хочет выполнить человек после отправки формы. Мы же об этом не знаем, поэтому и подходим к данному вопросу несколько иначе :).

Так это не секрет Smile
Это php скриптик который отправляет SMS(платный сервис) владельцу сайта, которое сообщает что была заполнена форма.

Аватар пользователя glu2006 glu2006 24 сентября 2009 в 17:42

Serega_od wrote:
Так это не секрет Smile
Это php скриптик который отправляет SMS(платный сервис) владельцу сайта, которое сообщает что была заполнена форма.

Ну вот теперь все более понятно :), тогда если у Вас подразумевается что таких форм может быть несколько + могут быть разные владельцы, то лучше конечно его не вставлять в вебформу, я бы все равно вынес этот скрипт в отдельную функцию и на событии save только вызывал бы функцию. +ы не надо при создании веб формы каждый раз создавать лишнее поле которое будет по сути дублироваться от ноды к ноде, оно вам надо? Smile
А если она единственная, то тут как хотите можете поступать.

Аватар пользователя Serega_od Serega_od 24 сентября 2009 в 17:47

"glu2006" wrote:
А если она единственная, то тут как хотите можете поступать.

Спасибо! Форма привязана к продукту - это форма заказа продукта.
Продукта есть 3 типа - для каждого своя форма + все эти формы еще и дублируются т.к. сайт двуязычный.
Т.е. правильнее всего в моем случае будет такой алгоритм: Создать отдельную функцию, запихнуть в неё мой скрипт отправки смс и затем вызывать эту функцию из всех моих форм с помощью события save hook_nodeapi. Вроде так?

Аватар пользователя VladoMire VladoMire 24 сентября 2009 в 19:13

"Serega_od" wrote:
Спасибо! Т.е. Всё что мне нужно - создать поле Additional Processing и поместить туда PHP код и где-то в настройках указать чтоб оно срабатывало при отправке формы?

Нет ничего создавать не надо. Все проще: Открываете Вашу анкету (или создаете новую), затем изменить (при создании новой в открывшихся настройках), ищете Webform advanced settings и там найдете это поле, что я писал Additional Processing . Туда загрузите Ваш код, который будет выполняться при отправке. Там может быть, что угодно и необходимо.

Можно эту задачу решить и другим способом, создать скрытое поле в самой анкете, но для этого подгрузить файл расширения вида hidden dinamic и уже туда загружать PHP код.

Но мне кажется проще первый вариант для этой задачи.

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

Но здесь по-моему перехват не нужен. Нужно сделать отправку SMS, но это делается при отправке анкеты. Перехват нужен был бы если в настройках самой анкеты невозможно было что-либо сделать. Тогда требуется перехват и выполнение дополнительного кода. А тут все редактируется как душе угодно, тем и хорош и гибок модуль Webform

Аватар пользователя Serega_od Serega_od 24 сентября 2009 в 21:22

"VladoMire" wrote:
Нет ничего создавать не надо. Все проще: Открываете Вашу анкету (или создаете новую), затем изменить (при создании новой в открывшихся настройках), ищете Webform advanced settings и там найдете это поле, что я писал Additional Processing . Туда загрузите Ваш код, который будет выполняться при отправке. Там может быть, что угодно и необходимо.

Можно эту задачу решить и другим способом, создать скрытое поле в самой анкете, но для этого подгрузить файл расширения вида hidden dinamic и уже туда загружать PHP код.

Но мне кажется проще первый вариант для этой задачи.

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

Но здесь по-моему перехват не нужен. Нужно сделать отправку SMS, но это делается при отправке анкеты. Перехват нужен был бы если в настройках самой анкеты невозможно было что-либо сделать. Тогда требуется перехват и выполнение дополнительного кода. А тут все редактируется как душе угодно, тем и хорош и гибок модуль Webform

Спасибо за подробное объяснение! Теперь знаю 2 варианта как это сделать Smile

Аватар пользователя VladoMire VladoMire 24 сентября 2009 в 23:09

"Serega_od" wrote:
Спасибо за подробное объяснение! Теперь знаю 2 варианта как это сделать :)

На здоровье:)))

Тут вообще эту задачу можно решить и другими вариантами (как это возможно в Drupal), но поскольку используете модуль Webform, проще решить его силами, без напряга и не выдумывать разные сложности.

Аватар пользователя Dan Dan 25 сентября 2009 в 3:54

"Serega_od" wrote:
Спасибо за подробное объяснение! Теперь знаю 2 варианта как это сделать :)

Я за решение hook_nodeapi. Оба решения будут работоспособны, но! Если у вас несколько продуктов и к каждому надо делать форму, то кол-во форм будет равно кол-ву продуктов да ещё помноженное на кол-во языков. Я правильно понял? Тоесть если продктов 10, а зыков - 2, то форм - 20. И если вам придётся что-то поменять в коде, то придётся отредактировать 20 форм, вместо одного места в модуле. Вообще есть правило: если какой-то блок код выполняется два и более раз - разумно сделать его функцией.

Решать Вам Smile

Аватар пользователя glu2006 glu2006 25 сентября 2009 в 9:57

Dan wrote:
Вообще есть правило: если какой-то блок код выполняется два и более раз - разумно сделать его функцией.
Решать Вам :)

+100500 Smile

"Золотые слова Юрий Бенедиктович, золотые слова".

Только я-бы слово "разумно" заменил на "обязательно".

Аватар пользователя VladoMire VladoMire 25 сентября 2009 в 10:37

Dan wrote:
Вообще есть правило: если какой-то блок код выполняется два и более раз - разумно сделать его функцией.

Решать Вам :)

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

Аватар пользователя Serega_od Serega_od 30 сентября 2009 в 22:00

"VladoMire" wrote:
Нет ничего создавать не надо. Все проще: Открываете Вашу анкету (или создаете новую), затем изменить (при создании новой в открывшихся настройках), ищете Webform advanced settings и там найдете это поле, что я писал Additional Processing . Туда загрузите Ваш код, который будет выполняться при отправке. Там может быть, что угодно и необходимо.

Подскажите еще пожалуйста как в коде "выципить" данные из формы? Т.е. в форме есть поля: Контакт, мыло контакта, заказанный продукт - вот как их в код php засунуть, как-то через token?

Аватар пользователя Serega_od Serega_od 30 сентября 2009 в 22:26

Пробовал вот так, но что-то не хочет:

$Product = $node->field_product[0]['value'];
$Contact = $node->field_name[0]['value'];
$Phone = $node->field_phone[0]['value'];
Аватар пользователя glu2006 glu2006 1 октября 2009 в 10:13

Serega_od wrote:
Пробовал вот так, но что-то не хочет:

На каком событии пробовали?
Точнее в какой момент вы вызываете свой скриптик в котором собираете данные для отправки смс?

Аватар пользователя Serega_od Serega_od 1 октября 2009 в 10:31

"glu2006" wrote:
На каком событии пробовали?
Точнее в какой момент вы вызываете свой скриптик в котором собираете данные для отправки смс?

Пока пробую на Additional Processing, которое в настройках вебформы. Скрипт срабатывает, смс уходит, но вот только в тело смс(в текст) не подставляются значения контакт, продукт, телефон...
Название полей я подставлл такие , которые указываются в Field Key при создании поля в WebForm, т.е. например при создании поля Phone в Field Key я указывал phone и соответственно делал так: $Phone = $node->field_phone[0]['value'], а потом уже в тело смс подставлял такую конструкцию:

<?php
$text 
"New mail at mysite.com".
", prod:" $Product .
", cont:" $Contact .
", pho:" $Phone .
", email:" $Email;
?>

А в СМС приходит только: "New mail at mysite.com, prod:, cont:, pho:, email:"

Аватар пользователя glu2006 glu2006 1 октября 2009 в 11:01

Ну тогда все правильно что там пусто Smile поскольку Вам необходимо, как и указывалось ранее делать отправку сообщения именно на hook_nodeapi событие save там объект $node уже полностью сформирован для сохранения и все переменные на своих местах, а так же проверена корректность и обязательность заполнения всех полей формы. т.е. в Вашем варианте я не исключаю возможной отправки смс даже с незаполненными полями и не отправленной формой :).

Аватар пользователя Serega_od Serega_od 1 октября 2009 в 11:04

"glu2006" wrote:
в Вашем варианте я не исключаю возможной отправки смс даже с незаполненными полями и не отправленной формой :)

Та не, если не заполнить обязательные поля то не отправляется Smile

Аватар пользователя Serega_od Serega_od 1 октября 2009 в 11:48

"glu2006" wrote:
hook_nodeapi событие save,

Почитал API.
Что-то не могу найти событие save, вижу только 'presave', 'insert', 'update', 'delete' и 'view':

<?php
function hook_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'presave':
      if ($node->nid && $node->moderate) {
        // Reset votes when node is updated:
        $node->score = 0;
        $node->users = '';
        $node->votes = 0;
      }
      break;
    case 'insert':
    case 'update':
      if ($node->moderate && user_access('access submission queue')) {
        drupal_set_message(t('The post is queued for approval'));
      }
      elseif ($node->moderate) {
        drupal_set_message(t('The post is queued for approval. The editors will decide whether it should be published.'));
      }
      break;
    case 'view':
      $node->content['my_additional_field'] = array(
        '#value' => theme('mymodule_my_additional_field', $additional_field),
        '#weight' => 10,
      );
      break;
  }
}
?>

Или надо в модуле WebForm искать где происходит событие Save и вешать на него hook_nodeapi() - блин совсем запутался Sad

Аватар пользователя Serega_od Serega_od 1 октября 2009 в 11:41

"andriy.olischuk" wrote:
Смотря что за форма. Если в ноде - то hook_nodeapi, если в комментарии, то hook_comment.
Для перехвата, к примеру, создаёте свой небольшой модуль mymodule и в нём функцию mymodule_nodeapi().
Как внутри этого хука обрабатывать события - можно посмотреть в официальной доке или гугле.

А свой модуль обязательно создавать?
Или как-то можно переопределить эту функцию в node.tpl.php?

Аватар пользователя Serega_od Serega_od 1 октября 2009 в 12:40

Я не силен в программировании(я не волшебник - я только учусь Smile ), но вот наваял пока такой кусок кода:


<?php
    
function mymodulename_hook_nodeapi (&$node) {
        if (
$node->nid == 'my_form_id') {
            
$Product $node->field_product[0]['value'];
            
$Contact $node->field_name[0]['value'];
            
$Phone $node->field_phone[0]['value'];
            
sendSMS($Product$Contact$Phone);
        }
    }
    
    function 
sendSMS($Product$Contact$Phone){
        
//MySCRIPT
    
}
?>

Вот тока куда это добро вставить?

Аватар пользователя glu2006 glu2006 1 октября 2009 в 13:15
<?php
function mymodulename_hook_nodeapi (&$node$op$a3$a4) {
 switch (
$op) {
    case 
'presave':
      if (
$node->type == 'webform') {
        
$Product $node->field_product[0]['value'];
        
$Contact $node->field_name[0]['value'];
        
$Phone $node->field_phone[0]['value'];
        
mymodulename_sendSMS($Product$Contact$Phone);
      }      
    break;
 }
}

function 

mymodulename_sendSMS($Product$Contact$Phone){
        
//MySCRIPT
}
?>

И это добро вставляете в файл своего модуля
mymodulename.module файл этот вместе с файлом mymodulename.info в папку mymodulename а папку в папку sites/all/modules
что писать в инфо файлах можно подсмотреть в любом модуле.

Аватар пользователя Serega_od Serega_od 1 октября 2009 в 15:18

Сделал свой моуль, назвал sendsms, вот инфо файл: sendsms.info

; $Id$
name = SendSMS
description = Send SMS.
core = 6.x

, вод модульный: sendsms.moule

<?php
function sendsms_hook_nodeapi (&$node, $op, $a3, $a4) {
 switch ($op) {
    case 'presave':
      if ($node->type == 'webform') {
        $Product = $node->field_product[0]['value'];
        $Contact = $node->field_name[0]['value'];
        $Phone = $node->field_phone[0]['value'];
        $Email = $node->field_email[0]['value'];
        $Date = $node->field_date[0]['value'];
        sendSMS($Product, $Contact, $Phone, $Email, $Date);
      }      
    break;
 }
}

function sendSMS($Product, $Contact, $Phone, $Email, $Date){
      //MyScript
}
?>

Затем зашел в админку, активировал модуль.
После отправляю форму - результат - тихо..как в танке..

Аватар пользователя glu2006 glu2006 1 октября 2009 в 15:49

Во первых function sendsms_nodeapi();
во вторых В процессе диалога, вылетело из головы, что модуль вебформ возможно не создает ноду под каждую отдельно оправленную форму, а пишет данные в свои таблицы, соответственно и хук этот возможно можно приложить разве что к голове Smile
Тогда по ходу нам необходимо перехватить событие webform_client_form_submit($form, &$form_state)
Для этого будем использовать hook_form_alter.
1. С помощью дебага вычисляем form_id оно уникально
2. На hook_form_alter подменяем значение submit на свое собственное, т.е. чтоб вызывалась функция из нашего-же модуля.
3. Собственно модуль:

<?php
function sendsms_form_alter(&$form$form_state$form_id) {
  if (
$form_id == 'то что надебажили') {
    
$form['submit'][] = 'mymodule_submit'//тут не уверен на 100% надо пробовать
  
}      
}

function 

mymodule_submit($form, &$form_state) {
  
$Product данные из поля формы//дебажим что и с какого элемента формы берется переменная $form_state
  
$Contact данные из поля формы;
  
$Phone данные из поля формы;
  
$Email данные из поля формы;
  
$Date данные из поля формы;
  
sendSMS($Product$Contact$Phone$Email$Date);
  
webform_client_form_submit($form, &$form_state);
}

function 

sendSMS($Product$Contact$Phone$Email$Date){
      
//MyScript
}

?>
Аватар пользователя Serega_od Serega_od 1 октября 2009 в 15:54

Спасибо!
Есть один маленький промежуточный вопросик по поводу:

"glu2006" wrote:
1. С помощью дебага вычисляем form_id оно уникально

В C++ через Visual Studio знаю как дебажить, а вот в PHP впервые слышу.
Это как-то через dev модуль?

P.S. Кстати пробовал и sendsms_hook_nodeapi и hook_nodeapi и sendsms_nodeapi - никак не работало Sad

Аватар пользователя Serega_od Serega_od 1 октября 2009 в 18:52

Вставил эту функцию:

<?php
function sendsms_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'webform_client_form_30') {
    $form['submit'][] = 'sendsms_submit';
}

начало выдавать ошибку на белом экране:
Fatal error: Cannot use string offset as an array in C:\wamp\www\ap1\includes\form.inc on line 984
Дальше не знаю что делать..
Пока добил Additional Processing, вот так вот правильно:

$Contact = $form_values['submitted_tree']['name'];
$Phone = $form_values['submitted_tree']['phone'];
$Email = $form_values['submitted_tree']['email'];

Таким образом СМС отправляется с нужными заполненными полями, только есть одно НО - после отправки формы вылазит WARNING такой:

    * warning: array_fill() [function.array-fill]: Number of elements must be positive in /home/mysite/public_html/includes/database.inc on line 253.
    * warning: implode() [function.implode]: Invalid arguments passed in /home/mysite/public_html/includes/database.inc on line 253.
    * warning: array_keys() [function.array-keys]: The first argument should be an array in /home/mysite/public_html/modules/user/user.module on line 502.
    * user warning: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1 query: SELECT p.perm FROM role r INNER JOIN permission p ON p.rid = r.rid WHERE r.rid IN () in /home/mysite/public_html/modules/user/user.module on line 502.

Как убрать этот ворнинг, и чего он вообще вылазит - всё же работает!!!
И что самое интересное после такой отправки формы происходит еще и LOGOUT пользователя!!!

Аватар пользователя Serega_od Serega_od 1 октября 2009 в 19:34

С Warning разобрался - у меня в моей функции sendSMS были переменные USER и PASSWORD - webforms это не понравилось, наверное аналогичные поля есть в её таблице) - заменил на POLZ и PAROL и WARNING перестал появляться Smile

Аватар пользователя WiseMan WiseMan 2 октября 2009 в 11:16

Если, таки, решите вернуться к реализацию через сниппеты внутри самой вебформы, то на странице handbook webform найдете правильный синтаксис для перехвата полей вебформы и примеры.

В частности поле  $Product = $node->field_product[0]['value']; в сниппете должно выглядеть вот так:
 $product = $form_values['submitted_tree']['field_product'];

Аватар пользователя Serega_od Serega_od 2 октября 2009 в 20:20

"WiseMan" wrote:
В частности поле $Product = $node->field_product[0]['value']; в сниппете должно выглядеть вот так:
$product = $form_values['submitted_tree']['field_product'];

Спасибо! Именно там я и нашел, смотрите на пару постов выше Smile
А со сниппетами так и не получилось: в function sendsms_form_alter выдаеет ошибку а nodeapi не работает