Drupal 7: Пишем собственный модуль рассылки по email при добавлении материалов на сайт используя SwiftMailer

test

Статья была обновлена, добавлены зависимости, блоки вывода подписки и архив с самим модулем. Смотреть здесь

Содержание

Предисловие

Озадачился я поиском модуля подписки по email при добавлениях материалов сайт. Так вот, хотелось чего-то простого, рабочего и не напряжного. Но увы, найти чего-то подпадающего под все эти критерии не удалось. Но что нам стоит самим написать такой модуль? Заранее извиняюсь за грамматику английского... Хотя возможно не только английского :-D

Что будем использовать?

- Стандартные средства drupal 7(меню, action, создание формы)
- Библиотеку работы с почтой SwiftMailer

Что такое подписка на рассылку новостей?

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

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

Прошлые статьи по написанию модулей для Drupal 7

Файловая структура модуля

Создаем папку модуля /sites/all/modules/esubscribes, в нем создаем папку core и заливаем содержимое библиотеки Swift, так чтобы у нас путь к подключаемому файлу от корня был:
/sites/all/modules/esubscribes/core/swift/lib/swift_required.php

Для модуля мы используем стандартные средства drupal 7 и библиотеку отправки писем SwiftMailer

Как и положено, создаем в корне модуля три файла:
esubscribes.install - при установке модуля отсюда берутся сведения об структуре нужной нам таблицы, которая впоследствии и создается.
esubscribes.info - информация об нашем модуле.
esubscribes.module - сам модуль.

Содержимое файлов ( c комментариями)

esubscribes.info

name=eSubscribes
description=module for subscribe updates materials via emails
package=Subscribes
version=0.99
core=7.x

По прошлым статьям должно быть понятно что здесь:
name - название модуля
description - описание модуля
package - категория к которой относиться модуль(группировка в списке модулей)
version - версия нашего модуля.
core - версия drupal с которой работает модуль. Как видно, у нас 7-ка.

esubscribes.install

<?
function esubscribes_schema() //ф-ция отвечает за таблицу данных для модуля, при включении создает ее, при удалении - удаляет
{
    $schema['esubscribes_emails']=array(//название таблицы в базе данных
        'description'=>'subscribers emails',//описание таблицы
        'fields'=>array(//в этом массиве идет список полей
           'id'=>array('type'=>'serial', 'unsigned'=>TRUE, 'not null'=>TRUE),//int unsigned auto_increment, должны сами знать... ID
           'email'=>array('type'=>'varchar','length'=>150,'not null'=>TRUE,'default'=>''),//сам email
                       ),
       'primary key'=>array('id'),//первичный ключ
// вообще можно было обойтись без поля id, только полем email,
//ну да ладно, оставим так сказать для масштабируемости нашего модуля
    );
    return $schema; //вот и возвращаем схему нашей таблицы
}

Как видно, в этих двух файлах нет ничего сложного. Дальше будет еще легче...

esubscribes.module

<?php
//наш action - действие которое мы будем выполнять
//подцепим его на триггер добавления нового материала
function esubscribes_action_info()
{
//возвращаем массив с определенным смыслом
    return array(
    'esubscribes_sends_emails_action'=>array(//функция которую будем выполнять
// при срабатывании триггера
        'type'=>'node',//тип содержимого с которым работает триггер, user, node, comment, etc...
        'label'=>t('esubscribes send emails'),//описание, используется при назначении этого действия
//какому-то триггеру
        'triggers'=>array('node_insert'/*,'node_update'*/),
//принадлежность триггерам, в нашем случае - добавление ноды
// и обновление закомментировано(включите если вам нужно), есть и другие варианты
        'configurable'=>FALSE,
//конфигурирование дает возможность отмечать маркеры которые будут передаваться в нашу функцию,
//для этого нужно создавать дополнительную форму, но мы делаем простой модуль, нам это не нужно
    ),
    );
}

//наш пункт в меню Навигация
function esubscribes_menu()
{
$items['subscribe'] = array(
'title' => t('Subscribe'),//название, функция t() - локализация
'page callback' => 'drupal_get_form',//говорим drupal-у что нам нужно загрузить форму
'page arguments'=>array('esubscribes_form'),//вот эту функцию, которая и содержим элементы
//нашей формы.
'access arguments' => array('access content'), //права доступа, такие же как и к контенту
'type' => MENU_NORMAL_ITEM,//тип нашей менюшки - обычная ссылка
  );
  return $items;
}

//сама форма
function esubscribes_form($form_state,&$form_submit)
{
//поле email
    $form['email']=array(
    '#title'=>t('Email'),//метка поля
    '#type'=>'textfield',//тип - текстовое поле
    '#required'=>TRUE,//обязательно к заполнению
    );

//подписываемся или отписываемся от рассылки
    $form['subscribe']=array(
    '#title'=>t('Unsubscribe'),
    '#type'=>'checkbox',//чекбокс
    '#default_value'=>0,//дефолтное значение
    '#return_value'=>1,//возвращаемое значение, если установлена галочка
    );

//наш submit отправляющий форму на обработку
    $form['submit']=array(
    '#type'=>'submit',
    '#value'=>'Submit',
    );

    return $form;
}

//сам обработчик нашей формы
function esubscribes_form_submit($form, &$form_state)
{
if ($form_state['values']['email'])//если у нас введен email
{
    $email = $form_state['values']['email'];//присваиваем его переменной, чтобы наглядней было
    if ($form_state['values']['subscribe'])//проверяем подписываемся или отписываемся
    {
        //Отписываемся
        if(validateemail($email))//проверяем на валидность введенный email
        {
            if(delemail($email))//проверяем удалось ли его удалить
            {
                drupal_set_message(t('Email was deleted!'));
//выводим сообщение об  успешном удалении
            }
            else
            {
                drupal_set_message(t('Email was not deleted!'));
//выводим сообщение о том что не смогли удалить по какой-то причине
            }
        }
        else
        {
            drupal_set_message(t('Not valid Email!'));
//если у нас email оказался не валидным, сообщаем пользователю об этом
        }
    }
    else //если мы подписываемся на рассылку
    {
        //Subscribe
        if (validateemail($email))//проверяем на валидность email
        {
            if (existemail($email))//проверяем не добавлен ли нам в базу уже такой email
            {
                drupal_set_message(t('This email already exist'));
//если есть такой, выводим сообщение
            }
            else//иначе, пробуем добавить в базу
            {
                if(addemail($email))//проверяем успешность добавления в БД
                {
                    drupal_set_message(t('Email was added!'));
//если успешно - выводим сообщение что добавили в базу
                }
                else//иначе
                {
                    drupal_set_message(t('Email was not added!'));
//выводим сообщение что не смогли добавить в базу
                }
            }
        }
        else
        {
            drupal_set_message(t('Not valid Email'));//снова же, выводим что email не валидный
        }
    }
}
else drupal_set_message(t('email is null'));
//если по каким-либо другим причинам не удалось обработать, говорим об этом пользователю
}

//функция проверяющая регулярным выражением валидность email
function validateemail($email)
{
    $regex = '/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/';
    if (preg_match($regex, $email)) { return true; } else { return false; }
}

//функция проверяющая существование такого email в базе
function existemail($email)
{
   return $nodes = db_select('esubscribes_emails', 'n')->fields('n', array('id', 'email'))->condition('email', $email)->countQuery()->execute()->FetchField();
}

//функция добавления email в базу данных
function addemail($email)
{
  return $nid = db_insert('esubscribes_emails')->fields(array('id' => 0,'email' => $email))->execute();
}

//функция удаления email из базы данных
function delemail($email)
{
   return $num_deleted = db_delete('esubscribes_emails')->condition('email', $email)->execute();
}

//само событие отправки писем на все занесенные в базу email-ы
function esubscribes_sends_emails_action($node)
{
//подключаем библиотеку Swift
    require_once 'core/swift/lib/swift_required.php';
//получаем список email-ов в массив
     $emails = db_select('esubscribes_emails', 'n')->fields('n', array('email'))->execute()->FetchCol();

//создаем транспорт для отправки писем(коннектимся на localhost, 25 порт
      $transport = Swift_SmtpTransport::newInstance('localhost', 25);
      // Создаем мейлер использующий ранее созданный $ransport
      $mailer = Swift_Mailer::newInstance($transport);

      // Создаем письмо
      $message = Swift_Message::newInstance("Рассылка LSoft IT: ".$node->title)//тему
        ->setFrom(array('no-reply@'.$_SERVER['SERVER_NAME'] => 'LSoft IT Blog'))//от кого отправляем
        ->setTo($emails)//массив с email-ами кому отправляем
//HTML вариант письма, кому нужно можете использовать его
//        ->setBody('На сайт был добавлен новый материал:<br>
//<a href="'.$_SERVER['SERVER_NAME'].'/node/'.$node->nid.'">'.$node->title.'</a>','text/html')
//а я использую для письма обычный текст
        ->setBody('На сайт был добавлен новый материал, прочесть можно по ссылке:
'.$_SERVER['SERVER_NAME'].'/node/'.$node->nid,'text/plain');
      //Делаем отправку писем
      $result = $mailer->send($message);
}

Почти все. Включаем наш модуль на странице модулей:
/admin/modules
Программно мы назначили наше событие в категорию добавление материала. Теперь свяжем его непосредственно с добавлением. Заходим
/admin/structure/trigger/node
Оно же через меню: Структура->События.
Выбираем в "Событие: документ добавлен" наше действие. Сохраняем.

Все. В меню видим нашу ссылку, добавляем свой email и добавляем новый материал для проверки. Может быть в следующей статье добавим еще блок для подписки, может даже используя Ajax, но на сегодня на этом все. И это будет только если будут пожелания в комментариях.

Итог

Сегодня Мы написали модуль для подписки/отписки рассылки читателями на email.

P.S. Пожелания и замечания приветствуются.

Google

Категория: 
Share/Save

Комментарии

test

Интересный вариант,спасибо за статью.
Возник такой вопрос, а можно-ли как-то по такому-же принципу сделать подписку на добавление материала отдельно взятого пользователя, т.е. к примеру на сайте N-ое количество пользователей каждый из которых добавляет материал на сайт в свой блог, соответственно кто-то захотел подписаться на получение уведомлений о добавлении материала каким-то отдельным пользователем т.е.не на все материалы сайта а только на те которые добавляет конкретно взятый пользователь.
Я в друпал новичок, может-быть поэтому не смог найти модуля с нужным функционалом, те что есть(Simplenews,Notifications) не дают такой возможности, может конечно недостаток знаний сказывается,но не смог я их настроить так как мне нужно, хотя-бы "пните" в нужном напрвлении меня, где искать?
Ещё раз спасибо.

test

Можно =) И сделать это достаточно не сложно, кроме некоторых ньюансов. В таком случае в таблице базы подписки Вы так же должны указывать на чей блог подписывается пользователь, то есть хранить (id,email,uid_author_blog), а в функции:
esubscribes_sends_emails_action($node) добавляем проверку

$emails = db_select('esubscribes_emails', 'n')->fields('n', array('email'))->condition('uid_author_blog', $node->uid,'=')->execute()->FetchCol();

Естественно Вам так же нужно теперь немного поправить функции проверки подписан ли такой человек на конкретного автора:

function existemail($email,$author_id)
{
   return $nodes = db_select('esubscribes_emails', 'n')->fields('n', array('id', 'email'))->condition('email', $email)->condition('uid_author_blog', $author_id)->countQuery()->execute()->FetchField();
}

//функция добавления email в базу данных
function addemail($email,$author_id)
{
  return $nid = db_insert('esubscribes_emails')->fields(array('id' => 0,'email' => $email))->condition('uid_author_blog', $author_id)->execute();
}

//функция удаления email из базы данных
function delemail($email,$author_id)
{
   return $num_deleted = db_delete('esubscribes_emails')->condition('email', $email)->condition('uid_author_blog', $author_id)->execute();
}

Остается поправить только сам момент подписки. Тут собственно несколько вариантов:
1) Вывести select с автодополнением с именами зарегистрированных пользователей на сайте, ведь по умолчанию блог есть у каждого зарегистрированного. Автодополнение поможет быстрее и проще ввести его данные.
2) Вшить форму подписки в сам шаблон темы, то есть в папке с темой внести код отображения формы подписки и передать в него UID автора блога.
3) Прочее... Я тоже не в идеале знаю друпал и уверен что есть более удачные решения чем перечисленные два. Основная задача в этом моменте в функцию подписки
function esubscribes_form_submit($form, &$form_state)
передать UID автора статьи которую смотрит пользователь.

Возможно выше описанного Вам хватит для решения своей задачи, если нет, напишите =) будет чуть больше свободного времени отпишусь по решению.

Never Give UP!

Делитесь с друзьями в социальных сетях! Оставляйте комментарии!

Share/Save

Это Вам так же может быть интересно!