Здравствуйте, уважаемые Хабровчане! Решил поделиться с вами довольно простым криворуким приёмом, как за 10 минут "поднять" чатик на "голом" yii2 с помощью pjax. Кому интересно про что речь, добро пожаловать под кат.
Думаю что большинство читателей, знакомых с yii2, также знакомы и с технологией pjax.
БД
От БД нам нужна всего 1 таблица с сообщениями, создадим её в свойственной yii манере, с помощью миграции:
$ ./yii migrate/create init
use yiidbMigration;
class m160923_115323_init extends Migration
{
public function up()
{
$this->createTable('message', [
'id' => $this->primaryKey(),
'from' => $this->integer()->notNull(),
'to' => $this->integer()->notNull(),
'text' => $this->text()->notNull()
]);
}
public function down()
{
$this->dropTable('message');
}
}
На данном этапе можно сразу описать модель сообщения с довольно важным методом, с помощью которого мы в дальнейшем будет получать экземпляр ActiveQuery для формирования самого чата:
namespace appmodels;
use yiidbActiveQuery;
use yiidbActiveRecord;
/**
* @property int $id
* @property int $from
* @property int $to
* @property string $text
*/
class Message extends ActiveRecord
{
public function rules()
{
return [
[['from', 'to', 'text'], 'required'],
[['from', 'to'], 'integer'],
['text', 'string']
];
}
/**
* @param int $from
* @param int $to
* @return ActiveQuery
*/
public static function findMessages($from, $to)
{
return self::find()
->where(['from' => $from])
->orWhere(['from' => $to, 'to' => $from]);
}
}
вот собственно и всё, что нам потребуется от БД.
Контроллер
Контроллер у нас будет состоять всего из одного "экшна":
namespace appcontrollers;
use appmodelsMessage;
use Yii;
use yiifiltersAccessControl;
use yiihelpersVarDumper;
use yiiwebController;
class ChatController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'roles' => ['@'],
]
],
]
];
}
public function actionIndex($id)
{
$currentUserId = Yii::$app->user->identity->getId();
$messagesQuery = Message::findMessages($currentUserId, $id);
$message = new Message([
'from' => $currentUserId,
'to' => $id
]);
if ($message->load(Yii::$app->request->post()) && $message->validate()) {
$message->save();
$message = new Message([
'from' => $currentUserId
]);
if (Yii::$app->request->isPjax) {
return $this->renderAjax('_chat', compact('messagesQuery', 'message'));
}
}
if (Yii::$app->request->isPjax) {
return $this->renderAjax('_list', compact('messagesQuery', 'message'));
}
return $this->render('chat', compact('messagesQuery', 'message'));
}
}
Постараюсь пояснить, что происходит в "экшне":
- При переходе на страницу загружается полностью контент вместе с layout
- После загрузки страницы запускается setInterval, который обновляет список сообщений
- При отправке сообщения в чат обновляется список совместно с формой
Вью
А вот тут, по моему мнению, самое интересное. Для начала постараюсь пояснить логику обновления "чатика" при помощи pjax:
В нашем случае нам нужно:
- Обернуть список с формой в pjax-контейнер для обновления всего списка сообщений и формы в случае отправки сообщения собеседнику;
- Обернуть только список в pjax-контейнер для периодического обновления списка сообщений.
<?php
/**
* @var yiiwebView $this
* @var appmodelsMessage $message
* @var yiidbActiveQuery $messagesQuery
*/
?>
<?php yiiwidgetsPjax::begin([
'timeout' => 3000,
'enablePushState' => false,
'linkSelector' => false,
'formSelector' => '.pjax-form'
]) ?>
<?= $this->render('_chat', compact('messagesQuery', 'message')) ?>
<?php yiiwidgetsPjax::end() ?>
<?php $this->registerJs(<<<JS
function updateList() {
$.pjax.reload({container: '#list-messages'});
}
setInterval(updateList, 1000);
JS
) ?>
<?php
/**
* @var yiiwebView $this
* @var appmodelsMessage $message
* @var yiidbActiveQuery $messagesQuery
*/
?>
<?php yiiwidgetsPjax::begin([
'id' => 'list-messages',
'enablePushState' => false,
'formSelector' => false,
'linkSelector' => false
]) ?>
<?= $this->render('_list', compact('messagesQuery')) ?>
<?php yiiwidgetsPjax::end() ?>
<?php yiiwidgetsActiveForm::begin(['options' => ['class' => 'pjax-form']]) ?>
<?= yiibootstrapHtml::activeTextarea($message, 'text') ?>
<?= yiihelpersHtml::submitButton('Отправить') ?>
<?php yiiwidgetsActiveForm::end() ?>
<?php
/**
* @var yiiwebView $this
* @var yiidbActiveQuery $messagesQuery
*/
?>
<?= yiiwidgetsListView::widget([
'itemView' => '_row',
'layout' => '{items}',
'dataProvider' => new yiidataActiveDataProvider([
'query' => $messagesQuery,
'pagination' => false
])
]) ?>
<?php
/**
* @var yiiwebView $this
* @var appmodelsMessage $model
*/
?>
<div class="row">
<div class="col-md-3"><?= $model->from ?></div>
<div class="col-md-9"><?= $model->text ?></div>
</div>
Результат
Автор: sluchainiyznak
Добрый день я всё зделал по инструкции,но выдаёт 404,
может нужно дополнительно устанавливать какието расширения?
Я бы тебя на работу не взял) Даже если учесть преимущество, что для чата на интервале не нужен демон. Зачем pjax + list ? Вызываешь метод обновления окна и параллельно очищаешь форму ввода при отправке, а по интервалу только вызываешь метод обновления окна… Хотя это все кастыли… Юзай вебсокеты!
А ты скинь пост, где показывается как его юзать, твой вебсокет. Я в интернете пошарил, везде с использованием js. А на чистом yii2 с php нет нигде.