Зачем нужна форма подписки?!! Допустим есть посетители вашего сайта, которым он нравится и они хотят быть в курсе обновлений, новых статей. Как они узнают, что произошли обновления? А что, если вам необходимо срочно сообщить что-то важное? Как увеличить посещаемость сайта?!!

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

В этой статье рассмотрим процесс создания такой формы на php-фреймворке Yii2.

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

Обязательный элемент - e-mail, на который будет отправляться письмо с уведомлением. Некоторые формы просят ввести имя человека, но это редко имеет смысл. Не все хотят светить данные о себе, кроме того это лишние телодвижения, если имя используется только для того, чтобы указать его обращаясь по имени в сообщении.

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

Итак форма будет иметь одно поле ввода и может выглядеть примерно так:

форма подписки1

При успешном сохранении данных в базу, покажем посетителю сайта такое уведомление:

форма подписки2

А если подписчик попробует ввести свой e-mail повторно, покажем ему:


форма подписки3

Форма будет проверяться, сохраняться, а уведомления выводиться без перезагрузки страниц. Это сделаем с помощью стандартного плагина Yii2 PJAX.

Проверить работу формы можно подписавшись на новые статьи на данном сайте! :)

Прежде всего подготовим базу данных. Для автоматического создания нужной таблицы и полей выполните миграцию:

public function safeUp()
{
    $tableOptions = null;
    if ($this->db->driverName === 'mysql') {
        $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB';
    }
    $this->createTable('{{%subscription}}', [
        'id' => $this->primaryKey(),
        'email' => $this->string()->notNull(),
        'addtime' => $this->string(),
    ], $tableOptions);
}
public function safeDown()
{
    $this->dropTable('{{%subscription}}');
}
Или можете создать вручную.

форма подписки phpMyAdmin

Как я и писал, дополнительно создадим поле для хранения даты подписки. Я привык хранить дату в виде строки (UNIX фомат), чтобы не иметь проблем с временными зонами.

Теперь необходимо создать модель, которая будет проверять введенные данные и поможет с сохранением их в БД. Для этого создайте файл (например Subscription.php) в папке common\models

<?php
namespace common\models;
use Yii;
class Subscription extends \yii\db\ActiveRecord{
    public static function tableName()
    {
        return '{{%subscription}}';
    }
    public function rules(){
        return [
            [['email'], 'required'],
            [['email'], 'email'],
            [['email'], 'trim'],
            [['email'], 'unique'],
            [['email', 'addtime'], 'string', 'max' => 255],
        ];
    }
    public function attributeLabels()
    {
        return [
            'id' => 'id',
            'email' => 'Email',
            'addtime' => 'Время добавления',
        ];
    }
}
В модели укажем такие правила:

  • e-mail - поле обязательное для заполнения;
  • будем проверять на корректность введенный электронный адрес;
  • удалим пробелы в начале и конце, если пользователь их случайно введет или скопирует;
  • сделаем проверку на уникальность (чтобы электронные адреса не повторялись);
  • ограничим длину наших полей.
Изначально модель я создавал с помощью генератора Gii, но большинство правил пришлось прописывать вручную, так что вам проще будет взять уже готовую.

Теперь создадим сам файл виджета SubscriptionWidget.php в папке common\widgets с таким содержимым:

<?php
/*
 * Кнопка подписки
 */
namespace common\widgets;
use Yii;
use yii\base\Widget;
use common\models\Subscription;
class SubscriptionWidget extends Widget {
    public $subscription;
    public function init() {
        $this->subscription = new Subscription();        
    }
    public function run() {
    return $this->render('subscription',[
            'model' => $this->subscription,            
        ]);
    }
}
Здесь просто создаем объект Subscription для работы с моделью и передаем его в файл-представление (вид) subscription.php. Для файлов видов виджетов, создадим в папке widgets папку views.

Вид будет такого содержания:



<?php
use yii\widgets\ActiveForm;
use yii\helpers\Html;
use yii\widgets\Pjax;
?>
<div class="sidebar_section subscription">
    <h4>Подписка</h4>
    <?php Pjax::begin(['enablePushState' => false, 'id' => 'pjax_form']); ?>
    <?php $form = ActiveForm::begin([
            'action' => yii\helpers\Url::to(['site/subscription']),
            'options' => [
                'data-pjax' => true,
            ],
        ]); ?>
    <?=$form->field($model, 'email')->textInput(['placeholder'=>'E-mail'])->label(false);?>
    <?=Html::submitButton('Подписаться',  ['class' => 'submit btn btn-default']); ?>
    <?php ActiveForm::end(); ?>
    <?php Pjax::end(); ?>
    <div style="clear:both;"></div>
</div>
Так как форму помещаем внутри Pjax, после ее отправки данные будем выводить вместо ее полей.

Как видно, форма передает данные в frontend\controllers\SiteController.php в метод (действие) actionSubscription(). Вот код метода:

//Форма подписки из виджета    
public function actionSubscription(){
    $model = new \common\models\Subscription();
    if ($model->load(Yii::$app->request->post()) && $model->validate()){
        $email = Html::encode($model->email);
        $model->email = $email;
        $model->addtime = (string) time();
        if ($model->save()) {                
            Yii::$app->response->refresh(); //очистка данных из формы
            echo "<p style='color:green'>Подписка оформлена!</p>";
            exit;
        } 
    } else {
        echo "<p style='color:red'>Ошибка оформления подписки.</p>";
        //Проверяем наличие фразы в массиве ошибки
        if(strpos($model->errors['email'][0], 'уже занято') !== false) {
            echo "<p style='color:red'>Вы уже подписаны!</p>";
        }          
    }        
    exit;
}
Основные моменты.
Получаем и проверяем нашу форму, если человек уже подписан (email есть в базе) выводится соответствующее сообщение. Дело в том, что проверка на уникальность, указанная в нашей модели

[['email'], 'unique'],

не выводит сообщение пользователю на этапе заполнения формы, поэтому тип ошибки получаем из массива $model->errors. Я использовал поиск подстроки 'уже занято' в строке ошибки. Для этого вывод ошибок должен быть на русском языке (настроить локализацию) или же измените данную фразу. Для локализации достаточно добавить параметр ‘language’ => ‘ru’, для advanced в файл - корневая/common/config/main.php, для basic в файл корневая/common/config/web.php.



Если по какой-то другой причине произошла ошибка - простое сообщение об ошибке. При успешном сохранении в БД, сообщение "Подписка оформлена". Так же перед сохранением данных в БД сохраняем текущую метку времени

$model->addtime = (string) time();

Данное действие не вызывает файл-вид т.к. все сообщения выводимые оператором echo будут отображаться вместо полей формы с помощью PJAX.

Для вызова виджета достаточно добавить строку

<?= common\widgets\SubscriptionWidget::widget() ?>
в нужный файл вида.

Все, форма готова, e-mail подписчиков сохраняются в базу данных. Дальше нужно создать рассылку уведомлений, об этом читайте в следующей статье. Не забудьте подписаться на моем блоге :)