Информация! Пример написан с использованием Bootstrap стилей и скриптов. При необходимость html, css и js Вы можете заменить на свой, это не повлияет на общую логику работы примера.
В конечном результате получи такую форму обратной связи:

И так приступим.
Создадим модель для формы обратной связи в папке /protected/models/, имя класса ContactForm, имя файла модели ContactForm.php, код модели (/protected/models/ContactForm.php):
<?php
class ContactForm extends CFormModel {
public $name;
public $email;
public $subject;
public $body;
public $verifyCode;
public function rules() {
return array(
array('name, email, body, verifyCode', 'required'),
array('email', 'email'),
array('verifyCode', 'captcha', 'on'=>'new'),
);
}
public function attributeLabels() {
return array(
'verifyCode' => 'Капча',
'name' => 'Имя',
'email' => 'Э-почта',
'body' => 'Сообщение',
);
}
}
Теперь создадим виджет для всплывающего окна формы обратной связи в папке с виджетами /protected/widgets/, имя класса FBModal, имя файла модели FBModal.php, код виджета (/protected/widgets/FBModal.php):
<?php
class FBModal extends CWidget {
public function init() {
$fBForm = new ContactForm('new');
$cs = Yii::app()->clientScript;
$cs->registerScriptFile(Yii::app()->theme->baseUrl . '/js/fbModal.js', CClientScript::POS_END);
//выводить новую капча при перезагрузки страницы
Yii::app()->controller->createAction('captcha')->getVerifyCode(true);
$this->render('webroot.themes.'.Yii::app()->theme->name.'.widgets.FBModal.fBForm', array('fBForm' => $fBForm));
}
}
Создадим представление (view) для виджета FBModal в папке /themes/themeName/widgets/FBModal/, имя файла fBModal.php, с кодом модального окна (/themes/themeName/widgets/FBModal/fBModal.php):
<!-- Модальное окно формы обратной связи -->
<div class="modal fade" id="fbModal" tabindex="-1" role="dialog" aria-labelledby="fbModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Форма обратной связи</h4>
</div>
<?php
$form = $this->beginWidget('CActiveForm', array(
'id' => 'uFBForm',
'action' => '/site/sendFBForm',
'enableAjaxValidation' => true,
'enableClientValidation' => true,
'method' => 'POST',
'clientOptions' => array(
'validateOnSubmit' => true,
'validateOnChange' => false,
'validateOnType' => false,
'afterValidate' => 'js:function(form, data, hasError) {if (!hasError) {fbModalSend();}}',
'errorCssClass' => 'has-error',
),
'errorMessageCssClass' => 'small text-danger',
'htmlOptions' => array('class' => 'contact-form', 'role' => 'form'),
));
?>
<div class="modal-body">
<div class="form-group">
<?php
echo $form->labelEx($fBForm, 'name');
echo $form->textField($fBForm, 'name', array(
'class' => 'form-control',
'placeholder' => 'Введите Ваше имя'
));
echo $form->error($fBForm, 'name');
?>
</div>
<div class="form-group">
<?php
echo $form->labelEx($fBForm, 'email');
echo $form->textField($fBForm, 'email', array(
'class' => 'form-control',
'placeholder' => 'Введите E-mail',
));
echo $form->error($fBForm, 'email');
?>
</div>
<div class="form-group">
<?php
echo $form->labelEx($fBForm, 'body');
echo $form->textArea($fBForm, 'body', array(
'rows' => 3,
'cols' => 40,
'class' => 'form-control',
'placeholder' => 'Введите текст сообщения'
));
echo $form->error($fBForm, 'body');
?>
</div>
<div class="text-right">
</div>
<?php if (CCaptcha::checkRequirements()): ?>
<div class="form-group">
<?php echo $form->labelEx($fBForm, 'verifyCode'); ?>
<div class="row">
<div class="col-md-4">
<?php
$this->widget('CCaptcha', array(
'buttonLabel' => '<br/>Новый код',
'id' => 'newCode'
));
?>
</div>
<div class="col-md-8">
<?php echo $form->textField($fBForm, 'verifyCode', array(
'class' => 'form-control',
'placeholder' => 'Введите текст указанный на картинке')
);
echo $form->error($fBForm, 'verifyCode');
?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<div class="modal-footer">
<?php
echo CHtml::htmlButton('Отмена', array(
'type' => 'reset',
'class' => 'btn btn-default',
'data-dismiss' => 'modal'
));
echo CHtml::submitButton('Отправить', array(
'class' => 'btn btn-primary'
));
?>
</div>
<?php
$this->endWidget();
?>
</div>
</div>
</div>
<!-- Всплывающее окно с информацией об успешной отправке сообщения -->
<div class="modal fade" id="fbModalOk" tabindex="-1" role="dialog" aria-labelledby="fbModalOkLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Форма обратной связи</h4>
</div>
<div class="modal-body">
<p>Сообщение успешно отправлено.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>
</div>
</div>
</div>
</div>
<!-- Всплывающее окно с информацией об ошибке при отправке сообщения (при необходимости) -->
<!-- ... -->
JavaScript файл для виджета (подключается в классе виджета FBModal, строка 9). Путь к файлу /themes/themeName/js/, имя файла fbModal.js. Скрипт скрывает модальное окно с формой обратной связи после успешной отправки сообщения, очищает поле с текстом сообщения и выводит окно с информацией об успешной отправке сообщения. Код (/themes/themeName/js/fbModal.js):
function fbModalSend() {
$('#fbModal').modal('hide');
$('#fbModalOk').modal('show');
$("#ContactForm_body").val("");
$("#ContactForm_verifyCode").val("");
$.ajax({
url: "/site/captcha?refresh=1",
dataType: 'json',
cache: false,
success: function(data) {
$('#yw1').attr('src', data['url']);
$('body').data('captcha.hash', [data['hash1'], data['hash2']]);
//обновим капчу после успешной отправки
$('#newCode_button').click();
}
});
}
Настройка капчи. Так как у нас в форме обратной связи используется стандартная капча фреймворка, а наш виджет может вызываться в любой части проекта (например в модуле), то внесем настройки капчи в класс предок контроллеров Controller который находиться в папке /protected/components/, файл Controller.php, код (/protected/components/Controller.php):
<?php
class Controller extends CController {
//...
public function actions() {
return array_merge(parent::actions(), array(
'captcha' => array(
'class' => 'CCaptchaAction',
'backColor' => 0xFFFFFF,
'maxLength' => 4,
'minLength' => 3,
//'clickableImage' => true,
//'width'=> 200,
//'height'=> 50,
)));
}
//...
}
Отправка формы обратной связи в контролере SiteController (для отправки формы обратной связи Вы можете использовать любой удобный для Вас контроллер). Код (/protected/controllers/SiteController.php):
<?php
class SiteController extends Controller {
//...
public function actions() {
return array_merge(parent::actions(), array(
'page' => array(
'class' => 'CViewAction',
),
));
}
//...
public function actionSendFBForm() {
if (Yii::app()->request->isAjaxRequest) {
$model = new ContactForm('ajax');
if (isset($_POST['ContactForm'])) {
$model->attributes = $_POST['ContactForm'];
if ($model->validate()) {
$message = '<p>Э-почта: ' . $model->email . '</p>'
. '<p>Имя: ' . $model->name . '</p>'
. '<p>Сообщение: ' . $model->body . '</p>';
// ... отправка сообщения администратору ...
echo CActiveForm::validate($model);
Yii::app()->end();
} else {
echo CActiveForm::validate($model);
}
}
Yii::app()->end();
} else {
throw new CHttpException(404, 'Указанная запись не найдена');
}
}
//...
}
Внимание! Обратите внимание на функцию actions, она возвращает массив с использованием функции php array_merge. Это сделано для того что бы не потерять настройки капчи, которые находятся в классе родителе Controller. Если этого не сделать, то при обращении к действиям (action) контроллера SiteController Вы получите ошибку в виде исключения с текстом: Действие CCaptchaValidator.action "captcha" задано неверно: действия не найдено в текущем контроллере. Такой способ возврата массива необходимо использовать во всех контроллерах в которых будет присутствовать форма обратной связи и которые будут вызывать метод actions. Альтернативный способ задать параметры капчи без использования array_merge:
<?php
class SomeController extends Controller {
//...
public function actions() {
return array(
'captcha' => array(
'class'=>'CCaptchaAction',
'backColor'=>0xFFFFFF,
'maxLength'=> 4,
'minLength'=> 3,
),
'page' => array(
'class' => 'CViewAction',
),
);
}
//...
}
Либо не используйте стандартную капчу (или вообще не используйте капчу).
Вызов формы обратной связи:
<!-- Ссылка(кнопка) вызова модального окна с формой обратной связи -->
<a href="#" data-toggle="modal" data-target="#fbModal">Обратная связь</a>
<?php
//Подключение виджета с формой обратной связи
$this->widget('application.widgets.FBModal');
?>
Информация! Не забудьте подключить Bootstrap стили и скрипты для работы всплывающего (модального) окна. Пример:
<?php
//...
$cs = Yii::app()->clientScript;
$cs->registerCssFile(Yii::app()->theme->baseUrl . '/css/bootstrap.min.css');
$cs->registerCssFile(Yii::app()->theme->baseUrl . '/css/style.css');
//...
$cs->registerScriptFile(Yii::app()->theme->baseUrl . '/js/ie8-responsive-file-warning.js',
CClientScript::POS_END, array('media' => 'lt IE 9'));
$cs->registerScriptFile(Yii::app()->theme->baseUrl . '/js/ie-emulation-modes-warning.js',
CClientScript::POS_END);
$cs->registerScriptFile('https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js',
CClientScript::POS_END, array('media' => 'lt IE 9'));
$cs->registerScriptFile('https://oss.maxcdn.com/respond/1.4.2/respond.min.js',
CClientScript::POS_END, array('media' => 'lt IE 9'));
$cs->registerScriptFile(Yii::app()->theme->baseUrl . '/js/bootstrap.min.js',
CClientScript::POS_END);
$cs->registerScriptFile(Yii::app()->theme->baseUrl . '/js/ie10-viewport-bug-workaround.js',
CClientScript::POS_END);
//...
$cs->coreScriptPosition = CClientScript::POS_END;
//...
или
<link rel="stylesheet" type="text/css" href="/themes/themeName/css/bootstrap.min.css" /> <link rel="stylesheet" type="text/css" href="/themes/themeName/css/style.css" /> <!-- ... --> <script type="text/javascript" src="/themes/themeName/js/ie8-responsive-file-warning.js" media="lt IE 9"></script> <script type="text/javascript" src="/themes/themeName/js/ie-emulation-modes-warning.js"></script> <script type="text/javascript" src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js" media="lt IE 9"></script> <script type="text/javascript" src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js" media="lt IE 9"></script> <script type="text/javascript" src="/themes/themeName/js/bootstrap.min.js"></script> <script type="text/javascript" src="/themes/themeName/js/ie10-viewport-bug-workaround.js"></script> <!-- ... -->
Все, форма обратной связи во сплывающем окне - готова. Дальнейшие доработки на Ваш вкус)
devreadwrite.com



Подборка адаптивных шаблонов для вашей CMS
Статьи по
Как получить и установить HTTPS сертификат на сайта

Комментарии
а где можно посмотреть js файлы?
ОтветитьВсе js скипты из bootstrap.
ОтветитьВзять их можно отсюда: http://getbootstrap.com/getting-started/#download
Или из любого стандартного примера bootstrap: http://getbootstrap.com/getting-started/#examples
Отдельный компонент всплывающего окна тут: http://getbootstrap.com/javascript/#modals
в коде имеются ошибки
ОтветитьГде именно? И что за ошибки?
ОтветитьДелала полностью по Вашей инструкции, возникла ошибка "Виджет FBModal не может найти представление "webroot.themes..widgets.FBModal.fBForm".", в чем может быть причина?
Ответитьвью fBForm должно лежать в папке
Ответитьwww/themes/названиеВашейТемы/widgets/FBModalфайл
fBForm.phpУ Вас так?
www - корень сайта
Ответитьда все так, по ошибке как будто бы нет имени темы webroot.themes..widgets.FBModal.fBModal
ОтветитьУ Вас в файле
Ответить/protected/config/main.phpпараметрthemeзадан?Пример:
return array('theme' => 'bootstrap',
'sourceLanguage' => 'en_US',
//...
);
Если нет, то добавьте его или задайте имя темы вместо
Yii::app()->theme->name:$this->render('webroot.themes.названиеТемы.widgets.FBModal.fBForm', array('fBForm' => $fBForm));удалось решить таким образом $this->render('webroot.themes.'.Yii::app()->theme->getName().'.widgets.FBModal.fBModal', array('fBForm' => $fBForm));
ОтветитьОшибка исчезла, однако форма по нажатию на ссылку не открывается
посмотрела в инспекторе виджет не подключается с формой, с чем это может быть связано?
ОтветитьТочно содержимое fBForm.php не выводится? Попробуйте вместо кода формы вывести что-нибудь другое, например текст.
Ответитьда, проблема именно в том, что содержимое не выводится, страница на этом месте стоит и дальше не грузит
ОтветитьЯсно, я сегодня правил код виджета, строка 86 должна содержать следующий код:
Ответить<?php endif; ?>Но я точно не помню, какая строка. Скопируйте код еще раз и вставьте у себя, если признаки будут те же, я проверю код примера еще раз
Добавьте в index.php:
Ответитьini_set('error_reporting', E_ALL);defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL', 3);
Что бы видеть все ошибки
$form = $this->beginWidget('CActiveForm', array(
Ответить'id' => 'uFBForm',
хотелось бы спросить, а откуда берется этот 'id' => 'uFBForm',
id формы, здесь он не на что не влияет. У Вас получилось решить проблему с формой?
Ответитьда, проблему с формой решить удалось, осталась одна проблема, после отправки сообщения, не отображается сообщение об успешной отправке
ОтветитьОкно с формой закрывается после отправки?
ОтветитьВ чем была проблема с формой?
проблема была в конфликте скриптов, то есть чисто мой косяк, а вот окно не закрывается, просто весит без признаков жизни, но письма идут на почту
ОтветитьЯ думаю у вас контроллер не отдает ответ. После отправки запроса на сервер что консоль в фаербаге говорит?
ОтветитьПосле отправки письма сделайте вывод
Ответитьecho CActiveForm::validate($model);
или
echo '[]';
Уважаемые пользователи! Если Вы задавали вопрос в комментариях и Вам ответили, то отпишитесь о результатах. Зачастую ответчик ждет обратной связи.
ОтветитьСпасибо большое за статью, все работает отлично, в моем случае просто был конфликт скриптов, единственное, у меня не сработала эта строка $this->render('webroot.themes.'.Yii::app()->theme->name.'.widgets.FBModal.fBForm', array('fBForm' => $fBForm));, но проблема решилась явным написанием названия тему вместо Yii::app()->theme->name
ОтветитьЕще раз спасибо автору, очень помог
Всегда рады помочь!
ОтветитьПростите за мою глупость... Но а где определяется почтовый адрес, куда шлется все это?
ОтветитьМетод
ОтветитьactionSendFBForm, строка 27:// ... отправка сообщения администратору ...Тут код отправки, например:
$name = '=?UTF-8?B?' . base64_encode($model->name) . '?=';$subject = '=?UTF-8?B?Сообщение ФОС?=';
$headers = "From: $model->name <{$model->email}>\r\n" .
"Reply-To: {$model->email}\r\n" .
"MIME-Version: 1.0\r\n" .
"Content-Type: text/plain; charset=UTF-8";
mail(yourEmail@example.com, $subject, $message, $headers);
Как то так)
У вас есть видеоуроки с исходниками на эту тему
ОтветитьЗдравствуйте, Жакс! Видео пока нет, такая идея обдумывается уже давно, пока видео уроки только в планах
ОтветитьЗдравствуйте, а где исходники на файлы и демо?
ОтветитьДобрый день, здесь без демо и исходников, все в статье)
ОтветитьА для YII2 есть пример?
ОтветитьВот: Yii2, форма обратной связи во сплывающем (модальном) окне
ОтветитьЗдравствуйте, спасибо на статью, вопрос есть возможность добавить в форму загрузку файлов, например картинок только png, jpg?
ОтветитьИ еще один вопрос, если пользователь авторизован вместо логина подставляю Yii::app()->user->name; а вот как подставить email утруждаюсь?
ОтветитьВроде Yii::app()->user->title
ОтветитьСпасибо, разобрался <?=$usersModel->email;?>?, а как по первому вопросу по загрузке файлов?
ОтветитьНе знаю, надо экспериментировать. Я тут мимо проходил)
Ответить