minishop2: Отправка одного письма всем менеджерам

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

Казалось бы, чего еще желать? 

Задача 

Письмо о заказе должно всем менеджерам отправляться одно, чтобы почтовый клиент в поле «Кому» отображал сразу всех.

Поиск решения

Изучение кода minishop2 немного расстроило, так как записанные в системной настройке ms2_email_manager через запятую адреса сначала разбиваются по отдельности, затем каждому отправляется письмо. Естественно, одному менеджеру одно письмо. Соответственно, для 3 менеджеров будут отправлены 3 письма.

Возьмем код функции miniShop2::sendEmail() и немного модифицируем, чтобы он корректно работал в Console:

<?php
    $email = 'first@email.ru';
    $subject = 'test multiple email';
    $body = 'no body set';
    if (!isset($modx->mail) || !is_object($modx->mail)) {
        $modx->getService('mail', 'mail.modPHPMailer');
    }
    $modx->mail->set(modMail::MAIL_FROM, $modx->getOption('emailsender'));
    $modx->mail->set(modMail::MAIL_FROM_NAME, $modx->getOption('site_name'));
    $modx->mail->setHTML(true);
    $modx->mail->set(modMail::MAIL_SUBJECT, trim($subject));
    $modx->mail->set(modMail::MAIL_BODY, $body);
    $modx->mail->address('to', trim($email));
    if (!$modx->mail->send()) {
        $modx->log(modX::LOG_LEVEL_ERROR,'An error occurred while trying to send the email: '.$modx->mail->mailer->ErrorInfo);
    }
    $modx->mail->reset();

Одно письмо отправляется успешно. Теперь в переменную $email запишем 2 адреса:

$email = 'first@email.ru,second@email.ru';
    <...>

Результат:

An error occurred while trying to send the email: Пожалуйста, введите хотя бы один адрес e-mail получателя.

Фокус не прошел. Но если сделать 2 строки с добавлением адреса?

$modx->mail->address('to', trim($email1));
$modx->mail->address('to', trim($email1));

Письмо успешно отправлено, при просмотре в поле «Кому» видим оба ящика, как и требуется.

Получается, что самый простой вариант отправки одного письма для рассматриваемого кода такой:

$emails = 'first@email.ru,second@email.ru';
    <...>
    foreach(explode(',', $emails) as $email) {
        $modx->mail->address('to', trim($email));
    }
    <...>

С одной стороны, мы поняли, как добавлять более одного получателя для письма. С другой, задача-то в другом: отправлять не абстрактные письма, а стандартные при смене статусов заказов. Самый простой вариант — немного отредактировать метод miniShop2::sendEmail(). Всего-то 4 строки, да и забыть об этом. Но как быть с обновлениями miniShop2? Забыть о них или после каждого обновления снова редактировать вручную основной класс?

Пойдем другим путем.

Расширение основного класса

Функция miniShop2::changeOrderStatus() имеет прекрасные строки в своем начале:

if (is_object($this->order) && method_exists($this->order, 'changeOrderStatus')) {
            return $this->order->changeOrderStatus($order_id, $status_id);
        }

Данная конструкция проверяет, существует ли метод changeOrderStatus() в классе-обработчике заказа, и вызывает его при успехе. Таким образом, нам достаточно создать расширенный класс заказа: 

  1. Создадим класс заказа msOrderHandlerCustom, являющийся наследником оригинального msOrderHandler, в каталоге /core/components/minishop2/custom/order/ 
  2. Скопируем в него метод miniShop2::changeOrderStatus() целиком
  3. Добавим метод sendEmail():
public function sendEmail($emails, $subject, $body = 'no body set') {

        if (!isset($this->modx->mail) || !is_object($this->modx->mail)) {
            $this->modx->getService('mail', 'mail.modPHPMailer');
        }
        $this->modx->mail->set(modMail::MAIL_FROM, $this->modx->getOption('emailsender'));
        $this->modx->mail->set(modMail::MAIL_FROM_NAME, $this->modx->getOption('site_name'));
        $this->modx->mail->setHTML(true);
        $this->modx->mail->set(modMail::MAIL_SUBJECT, trim($subject));
        $this->modx->mail->set(modMail::MAIL_BODY, $body);
        foreach(explode(',', $emails) as $email) {
            $this->modx->mail->address('to', trim($email));
        }
        if (!$this->modx->mail->send()) {
            $this->modx->log(modX::LOG_LEVEL_ERROR,'An error occurred while trying to send the email: '.$this->modx->mail->mailer->ErrorInfo);
        }
        $this->modx->mail->reset();
    }
  1. В системную настройку ms2_order_handler_class запишем название нового класса msOrderHandlerCustom

Теперь у нас должен получиться механизм, который воспринимает несколько адресов через запятую и отправляет одно письмо сразу всем. Звучит красиво, но на практике никаких изменений: все еще каждому получателю собственное письмо.

Смотрим, что мы упустили: не смотрели внимательно на метод changeOrderStatus(), который меняет статус заказа и отправляет письма при необходимости. В нем есть неприятный момент:

$emails = array_map('trim', explode(',', $this->modx->getOption('ms2_email_manager', null, $this->modx->getOption('emailsender'))));
                if (!empty($subject)) {
                    foreach ($emails as $email) {
                        if (preg_match('/^[^@а-яА-Я]+@[^@а-яА-Я]+(?<!\.)\.[^\.а-яА-Я]{2,}$/m', $email)) {
                            $this->sendEmail($email, $subject, $body);
                        }
                    }
                }

Здесь происходит разбиение строки адресов на массив и запуск доработанной ранее функции для каждого отдельного адреса. Скопируем полностью метод changeOrderStatus() в наш расширенный класс и в приведенном выше куске кода оставим только малую его часть:

$emails = $this->modx->getOption('ms2_email_manager', null, $this->modx->getOption('emailsender'));
                if (!empty($subject)) {
                    $this->sendEmail($emails, $subject, $body);
                }

Теперь в метод отправки писем передается строка со списком адресов. Очень важный момент: мы полностью вырезали проверку корректности адресов. В текущем варианте даже некорректный адрес вида gsdsgfsdgf.rtgfsdgsdgf_dfgd будет добавлен в список получателей. Чтобы исключить такую неприятность, введем исключенную проверку в метод msOrderHandlerCustom::sendEmail():

$emails = array_map('trim', explode(',', $emails));
        foreach ($emails as $email) {
            if (preg_match('/^[^@а-яА-Я]+@[^@а-яА-Я]+(?<!\.)\.[^\.а-яА-Я]{2,}$/m', $email)) {
                $this->modx->mail->address('to', trim($email));
            }
        }

Проверяем и радуемся!

После выполнения всего вышеперечисленного задача решена, а оригинальный код miniShop2 не затронут, что позволяет успешно его обновлять.

Дата публикации: 2016-02-04 13:22:36
G+

Закрыть

Вернуться

Вернуться

Обратный звонок