Евгений Дурягин

Евгений Дурягин

Был в сети 15 декабря 2018, 13:04
Заказы не принимаю
насчет FormItAutoResponder подумаю как прикрутить.

Ну если кто и будет это делать, то просто создать еще один сниппет, который понимает парметры FormItAutoResponder и добавляет еще одно письмо в очередь.

Я для своего хука так и делал. Через FormIt можно указать несколько получателей в параметре &emailTo, я на каждого создавал отдельное письмо в очереди.
Конечно нет. К тому же я его не сам писал, а взял из FormIt github.com/Sterc/FormIt/blob/develop/core/components/formit/src/FormIt/Hook/Email.php#L61
Просто убрал все лишнее что сейчас не нужно было мне и адаптировал под компонент.

И он на первое время сойдет, но для полноценной замены желательно чтобы поддерживал все параметры FormIt, такие как скрытые копии, html или текст сообщение, вложения и прочее.
docs.modx.com/extras/revo/formit/formit.hooks/formit.hooks.email

Можно не все их в таблицу добавлять, оставить только важные, которые отображать в компоненте, а остальные в поле properties в json-виде, так расширять можно будет без правки схемы. Главное чтобы скрипт отправки поддерживал.

И у FormIt есть еще хук FormItAutoResponder docs.modx.com/extras/revo/formit/formit.hooks/formit.hooks.formitautoresponder
Это бывает полезно для обратной связи когда email уходит менеджеру, а пользователю дополнительно отправляется другой email со своим шаблоном «Спасибо за ваш отзыв. Менеджер уже занимается вашим вопросом»
И кстати с большим кол-вом писем могут быть проблемы. В скрипте не обнаружил защиту от повторного запуска скрипта.
Допустим лимит стоит 50 писем за раз, а запуск скрипта каждую минуту.
В большинстве случаев все работает и 50 писем успевают отправится за 1 минуту.
Но в какой-то час SMTP или сеть начнет тормозить и отправка станет занимать 3-5 сек.
За минуту успеют отправится только 20 писем, затем запуститься второй скрипт и начнет отправлять оставшиеся 30 письма, т.к. они еще не помечены как отправленные. В итоге пользователю будут приходить дубли.
Ну чтобы письма обратной связи и прочие тоже отправлялись через очередь.
Вот сейчас отправлять нужно от домена заказчика, а чтобы соблюсти все DKIM, SPF и прочее без правки DNS вариант только через доступ по SMTP.
А коннект к SMTP визуально секунды 3 и это тормозит на фронте.
Плюс опять же возможны какие-то лимиты по кол-ву в час, одновременных соединений и тп.
И у пользователя возникает ошибка и форма не отправляется.
Пример сниппета для drop-in replacement замены хука email для FormIt/AjaxForm
Просто в вызове поменять хук на email_queue (или свое название сниппета)
[[!Formit?
    &hooks=`email_queue`
    &emailTpl=`feedbackEmail`
    &emailTo=`test@mail.ru`
    &emailSubject=`Сообщение с сайта`
    &replyTo=`[[+email]]`
    &emailFrom=`[[++emailsender]]`
]]
Поддержку вложений не делал, т.к. не было необходимости.
И не все параметры FormIt поддерживает (например emailHtml, emailToName, emailCC, итд), т.к. компонент их не учитывает.

<?php

$fields = $hook->getValues();

$tpl = $modx->getOption('emailTpl', $hook->formit->config, '');
/* get from name */
$emailFrom = $modx->getOption('emailFrom', $hook->formit->config, '');
if (empty($emailFrom)) {
    $emailFrom = !empty($fields['email']) ? $fields['email'] : $modx->getOption('emailsender');
}
$emailFrom = $hook->_process($emailFrom, $fields);
$emailFromName = $modx->getOption('emailFromName', $hook->formit->config, $modx->getOption('site_name', null, $emailFrom));
$emailFromName = $hook->_process($emailFromName, $fields);

/* get subject */
$useEmailFieldForSubject = $modx->getOption('emailUseFieldForSubject', $hook->formit->config, true);
if (!empty($fields['subject']) && $useEmailFieldForSubject) {
    $subject = $fields['subject'];
} else {
    $subject = $modx->getOption('emailSubject', $hook->formit->config, '');
}
$subject = $hook->_process($subject, $fields);
/* check email to */
$emailTo = $modx->getOption('emailTo', $hook->formit->config, '');
$emailToName = $modx->getOption('emailToName', $hook->formit->config, $emailTo);
if (empty($emailTo)) {
    $hook->errors['emailTo'] = $modx->lexicon('formit.email_no_recipient');
    $modx->log(\modX::LOG_LEVEL_ERROR, '[FormIt] '.$modx->lexicon('formit.email_no_recipient'));
    return false;
}
/* compile message */
$origFields = $fields;
if (empty($tpl)) {
    $tpl = 'fiDefaultEmailTpl';
    $f = [];
    $multiSeparator = $modx->getOption('emailMultiSeparator', $hook->formit->config, "\n");
    $multiWrapper = $modx->getOption('emailMultiWrapper', $hook->formit->config, "[[+value]]");
    foreach ($fields as $k => $v) {
        if ($k == 'nospam') {
            continue;
        }
        if (is_array($v) && !empty($v['name']) && isset($v['error']) && $v['error'] == UPLOAD_ERR_OK) {
            $v = $v['name'];
            $f[$k] = '<strong>'.$k.'</strong>: '.$v.'<br />';
        } elseif (is_array($v)) {
            $vOpts = array();
            foreach ($v as $vKey => $vValue) {
                if (is_string($vKey) && !empty($vKey)) {
                    $vKey = $k.'.'.$vKey;
                    $f[$vKey] = '<strong>'.$vKey.'</strong>: '.$vValue.'<br />';
                } else {
                    $vOpts[] = str_replace('[[+value]]', $vValue, $multiWrapper);
                }
            }
            $newValue = implode($multiSeparator, $vOpts);
            if (!empty($vOpts)) {
                $f[$k] = '<strong>'.$k.'</strong>:'.$newValue.'<br />';
            }
        } else {
            $f[$k] = '<strong>'.$k.'</strong>: '.$v.'<br />';
        }
    }
    $fields['fields'] = implode("\n", $f);
} else {
    /* handle file/checkboxes in email tpl */
    $multiSeparator = $modx->getOption('emailMultiSeparator', $hook->formit->config, "\n");
    if (empty($multiSeparator)) {
        $multiSeparator = "\n";
    }
    if ($multiSeparator == '\n') {
        $multiSeparator = "\n"; /* allow for inputted newlines */
    }
    $multiWrapper = $modx->getOption('emailMultiWrapper', $hook->formit->config, "[[+value]]");
    if (empty($multiWrapper)) {
        $multiWrapper = '[[+value]]';
    }
    foreach ($fields as $k => &$v) {
        if (is_array($v) && !empty($v['name']) && isset($v['error']) && $v['error'] == UPLOAD_ERR_OK) {
            $v = $v['name'];
        } elseif (is_array($v)) {
            $vOpts = array();
            foreach ($v as $vKey => $vValue) {
                if (is_string($vKey) && !empty($vKey)) {
                    $vKey = $k.'.'.$vKey;
                    $fields[$vKey] = $vValue;
                    unset($fields[$k]);
                } else {
                    $vOpts[] = str_replace('[[+value]]', $vValue, $multiWrapper);
                }
            }
            $v = implode($multiSeparator, $vOpts);
            if (!empty($vOpts)) {
                $fields[$k] = $v;
            }
        }
    }
}
$message = $hook->formit->getChunk($tpl, $fields);
$message = $hook->_process($message, $this->config);


if (!$EmailQueue = $modx->getService('emailqueue', 'EmailQueue', $modx->getOption('emailqueue_core_path', null,
	$modx->getOption('core_path') . 'components/emailqueue/') . 'model/emailqueue/', array())) {
	$hook->addError('email', 'При отправке произошла ошибка');
	return false;
}

$data = array(
	'sender_package' => 'FormIt',
	'from' => $emailFrom,
	'from_name' => $emailFromName,
	'subject' => $subject,
	'body' => $message,
	'date' => date("Y-m-d H:i:s"),
);

$emailReplyTo = $modx->getOption('emailReplyTo', $hook->formit->config, '');
if (!empty($emailReplyTo)) {
    $date['replyto'] = $emailReplyTo;
}
$emailTo = array_map('trim', explode(',', $emailTo));

foreach ($emailTo as $to) {
    $to = $hook->_process($to, $fields);
    if (!empty($to)) {
        $data['to'] = $to;
        $queue_email = $modx->newObject('EmailQueueItem');
        $queue_email->fromArray($data);
        $queue_email->save();
    }
}

return true;
Что комментарием как вы хотите, что при смене статуса так и так письмо пользователю придет.
Причину отмены можно указывать в комментарии заказа, который вставить в шаблон письма.
Если клиенту не нравится что заказ отменен, то создайте свои статусы на разные случаи с уникальными шаблонами: уточнение данных, ожидание поступления итд.
Если комментарии шаблонные и их немного (товар в другом городе и будет через 3 дня, товар на складе и отправится в течении дня итд), то можно через статусы заказа. Письма на смену статуса пользователю приходят.

Например, в комментарии заказа указать что товар будет на складе через 3 дня и поменять статус на «ожидание поступления». Для каждого статуса можно указать чанк письма, где и вывести комментарий.
В качестве ограничения доступа только для одного компьютера можно рассмотреть вариант двойной аутентификации.
При авторизации пользователя отправлять ему смс с кодом, который он должен ввести на сайте.
Для пользователя неудобство будет только если вдруг авторизация слетела или он решил авторизоваться в другом браузере/устройстве/компе.
Если он будет передавать логин и пароль другим, то еще дополнительно нужно будет сообщать коды из смс при каждой авторизации. Думаю это быстро ему надоест.
Можно отправлять и по e-mail, т.к. отправка смс платная, но пользователь может создать спец. ящик и сообщать доступ к нему вместе с логином и паролем от сайта, или использовать временный ящик типа tempinbox.com
Тормозит именно этот метод, причем походу на любом хостинге при кол-ве товаров > 1-2 тыс.
Единственные варианты сейчас это
1. Закомментить эту строчку в процессоре
2. Перевести документы (хотя бы большую часть, например товары) на использование Freeze URI. Эти документы refreshUri не обновляет
3. Оптимизирвать RefreshUri и отправить Pull Request :)
Потому что в 2.2.15 не было вызова refreshURIs в процессоре очистки кэша github.com/modxcms/revolution/blob/release-2.2/core/model/modx/processors/system/clearcache.class.php

Вот обсуждение зачем они его добавили github.com/modxcms/revolution/issues/9129

Но самое интересное то, что Jason Coward писал, что такие вещи нужно запускать из командной строки на больших сайтах forums.modx.com/thread/85073/how-can-i-recalculate-uri-in-a-large-site-content-with-more-than-1-000-000-entries-without-server-timeout-for-the-script#dis-post-469206 Ну а теперь это при каждой очистке кэша