
В этом всем поможет создание формы подписки для вашего сайта с целью сборка электронных адресов людей, заинтересованных в вашем ресурсе, для последующей рассылки сообщений электронной почтой.
В этой статье рассмотрим процесс создания такой формы на php-фреймворке Yii2.
Внешний вид формы каждый может настроить под себя с помощью CSS, а мы сосредоточим внимание на главном. Какие данные нужны для создание рассылки?
Обязательный элемент - e-mail, на который будет отправляться письмо с уведомлением. Некоторые формы просят ввести имя человека, но это редко имеет смысл. Не все хотят светить данные о себе, кроме того это лишние телодвижения, если имя используется только для того, чтобы указать его обращаясь по имени в сообщении.
По-моему полезнее было бы узнать дату подписки, чтобы анализировать как давно человек подписан, когда кол-во подписавшихся было больше, когда меньше... Тем более, что для этого не потребуется просить ввести ее посетителю.
Итак форма будет иметь одно поле ввода и может выглядеть примерно так:

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

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

Форма будет проверяться, сохраняться, а уведомления выводиться без перезагрузки страниц. Это сделаем с помощью стандартного плагина 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}}'); }Или можете создать вручную.

Как я и писал, дополнительно создадим поле для хранения даты подписки. Я привык хранить дату в виде строки (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 - поле обязательное для заполнения;
- будем проверять на корректность введенный электронный адрес;
- удалим пробелы в начале и конце, если пользователь их случайно введет или скопирует;
- сделаем проверку на уникальность (чтобы электронные адреса не повторялись);
- ограничим длину наших полей.
Теперь создадим сам файл виджета 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 подписчиков сохраняются в базу данных. Дальше нужно создать рассылку уведомлений, об этом читайте в следующей статье. Не забудьте подписаться на моем блоге :)