Створення блогу на Symfony 2.8 lts [ Частина 5.1]

Привіт, Хабр! Хочу трохи вклинитися в цикл статей і показати як можна простим шляхом зробити оновлення списку коментарів у стрічці в режимі реального часу. Як це відбувається, наприклад, на github

Навігація по частинах керівництваЧастина 1 — Конфігурація Symfony2 і шаблонів
Частина 2 — Сторінка з контактною інформацією: валідатори, форми та електронна пошта
Частина 3 — Doctrine 2 і Фікстури даних
Частина 4 — Модель коментарів, Репозиторій та Міграції Doctrine 2
Частина 5 — Twig розширення, Бічна панель(sidebar) і Assetic



Для реалізації цієї задачі будемо використовувати сервіс Post Hawk.

Встановлюємо залежності
Перше, що нам потрібно, це додати в composer.json залежність:
composer require post-hawk/hawk-api-bundle ~1.0

Або якщо ви переключилися безпосередньо на гілку 5.1, то достатньо просто
composer update

і дочекатися установки пакета.

Далі встановлюємо erlang. Білди під різні системи знаходяться тут, або, якщо є бажання, можна зібрати з исходников.

Клонируем сервер і клієнт
git clone https://github.com/postHawk/hawk_client.git
git clone https://github.com/postHawk/hawk_server


Збираємо rebar:
$ git clone git://github.com/rebar/rebar.git
$ cd rebar
$ ./bootstrap

одержаний файлик (rebar) копіюємо в обидва репозиторію. Він нам потрібен для складання проекту.

Проект використовує 2 версію rebar. Під rebar3 поки не вдається запустити


Переходимо в папку з сервером, збираємо і запускаємо його:
cd hawk_server
nano src/hawk_server.app.src
#заповнюємо дані про користувача

{env, [
{statistic, [{use, false}]},
user, #{
<<"login">> => <<"symblog">>,
<<"-">> => [ %список доменів, з яких будуть прийматися підключення
<<"127.0.0.1:8000">>
],
<<"key">> => <<"very secret key">> %api ключ. Повинен збігатися на сервері і клієнті
}}
]}

mv .erlang .erlang_
rebar get-deps compile
mv .erlang_ .erlang

erl -name 'hawk_server@127.0.0.1' -boot start_sasl -setcookie test -kernel inet_dist_listen_min 9000 inet_dist_listen_max 9005


Аналогічно збираємо і запускаємо клієнт:
cd hawk_client
nano src/hawk_client.app.src
#заповніть назва server_node, наприклад, 'test_hawk_server@127.0.0.1' і api_key (повинен збігатися з серверним). Збережіть файл

{env, [
{api_key, <<"very secret key">>},
{server_node, 'hawk_server@127.0.0.1'}
]}

mv .erlang .erlang_
./rebar get-deps compile
mv .erlang_ .erlang
erl -name 'hawk_client@127.0.0.1' -boot start_sasl -setcookie test -kernel inet_dist_listen_min 9000 inet_dist_listen_max 9005


Якщо потрібно запустити процес у фоні, просто додайте до набору параметрів опцію -detached
Для користувачів windows утиліту запуску варто змінити з erl melle
Допрацьовуємо блог

Кофігурація бандла:

//app/AppKernel.php
$bundles = array(
...
new Hawk\ApiBundle\HawkApiBundle(),
new FOS\JsRoutingBundle\FOSJsRoutingBundle(),
);

#app/config/config.yml
hawk_api:
client:
host: '%hawk_api.client.host%' #ip або домен
port: '%hawk_api.client.port%' #порт, який слухає клієнт
key '%hawk_api.client.key%'

#app/config/parameters.yml
parameters:
hawk_api.client.host: 127.0.0.1
hawk_api.client.port: 7777
hawk_api.client.key: 'very secret key'

#app/config/routing.yml
hawk:
resource: '@HawkApiBundle/Controller/'
prefix: /hawk

fos_js_routing:
resource: "@FOSJsRoutingBundle/Resources/config/routing/routing.xml"


Ставимо assets:
php app/console assets:install --web symlink


Допрацьовуємо контролер:

...
use Blogger\BlogBundle\Entity\Blog;
use Hawk\ApiBundle\Event\GroupMessage;

У функцію додавання коментаря поміщаємо відправку повідомлень:
...
$em->persist($comment);
$em->flush();

$this->sendNotification($comment, $blog);

return $this->redirect($this->generateUrl('BloggerBlogBundle_blog_show', array(
...

ну і додаємо саму функцію:

Код
/**
* Відправлення повідомлення про нові коментарі
* @param Comment $comment коментар
* @param Blog $blog блоґ
*/
private function sendNotification(Comment $comment, Blog $blog)
{
//формуємо тіло коментаря
$comment_text = $this->renderView('BloggerBlogBundle:Comment:index.html.twig', [
'comments' => [$comment]
]);

//формуємо повідомлення
$gMessage = new GroupMessage();
$gMessage
->setFrom('comment_demon')
->setGroups(['blog_' . $blog->getId()])
->setText(['comment' => $comment_text])
->setEvent('new_comment') //буде згенерований на клієнті
;

//відсилаємо
$api = $this
->container
->get('event_dispatcher')
->dispatch(GroupMessage::NEW_MESSAGE, $gMessage)
->getResult() //HawkApi
;

//якщо виникли помилки пишемо їх в лог
if($api->hasErrors()){
$logger = $this- > get('logger');
$logger->error('Error sending message:' . print_r($api->getErrors(), 1));
}
}



Трохи зупинюся на тому, що тут відбувається. Відправка повідомлень через сервіс можлива двома способами. Перший це на прикладі вище, через систему подій symfony. Створюється об'єкт повідомлення (простого або групового) і надсилається з певним типом події. Другий варіант — це відправка безпосередньо з допомогою апі, яке можна отримати з контейнера:
$api = $this- > get('hawk_api.api')->getApi();
$api
->registerUser($id)
->sendMessage($from, $to, $text, $event)
->execute()
->getResult('sendMessage')
;


Допрацьовуємо шаблони:

У src/Blogger/BlogBundle/Resources/views/Blog/show.html.twig міняємо рядок
<article class="blog">

на
<article class="blog" data-blog-id="{{ blog.id }}">

, так як нам потрібен буде id блогу для підписки користувача.

Підключаємо скрипти:
{#src/Blogger/BlogBundle/Resources/views/layout.html.twig#}
{% block javascripts %}
{% javascript
'@BloggerBlogBundle/Resources/public/js/*'
output='js/plugins,js'
filter='?yui_js'
%}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
{% javascript
'../vendor/post-hawk/hawk-api/Resources/public/js/hawk_api.min.js'
%}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
<script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script>
<script src="{{ path('fos_js_routing_js', { callback: 'fos.Router.setData' }) }}"></script>
{% endblock %}


Ну і пишемо трохи js

код
$(document).ready(function () {
connectToHawk();
});

function connectToHawk()
{
//відправляємо запит за токеном
$.post(Routing.generate('hawk_token', {
useSessionId: 1
}), {}, function (data) {
if(data.errors === false){
//ініціалізуємо підключення
HAWK_API.init({
user_id: data.result.id
token: data.result.token,
url: data.result.ws,
debug: true
});

//підписуємося на нові коментарі
HAWK_API.bind_handler('new_comment', function(e, msg){
//ігноруємо службові повідомлення
if(msg.from === 'hawk_client')
return;
//знаходимо список коментарів і останній з них
//створюємо об'єкт нового
var $comments = $('.previous-comments'),
$last = $comments.find('.comment:last'),
cls = 'odd',
$comment = $(msg.text.comment)
;

//визначаємося з класом коментаря
if($last.size()){
cls = $last.hasClass('odd') ? 'even' : 'odd';
}

$comment
.removeClass('odd')
.addClass(cls)
.hide()
;
//показуємо
$comments.append($comment);
$comment.show('normal')
});

//підписуємося на нові коментарі
HAWK_API.bind_handler('open', function(e, msg){
var id = $('.blog').data('blogId');
//додаємо користувача в групу блогу
//якщо її немає, то вона буде створена з публічним доступом
HAWK_API.add_user_to_group(['blog_' + id]);
});
} else {
if(data.errors !== 'no_user') {
console.error(data);
}
}
});
}



Перше, що ми робимо, це відправляємо запит за токеном для підключення до сервера повідомлень. Так як користувач у нас не аторизованный, то говоримо контролеру використовувати в якості id користувача, id його сесії.
Якщо все добре, то ми отримаємо відповіді: id користувача, токен підключення та адресу сервера.
Далі, ініціалізуємо підключення і підписуємося на події. У даному разі нас цікавлять два з них. Перше — open, виникає після успішного підключення до сокета. Друге — new_comment (його ми передаємо при відправці повідомлення), безпосередньо новий коментар.

Ось власне і все. Дякую за увагу. Код цієї частини доступний на github у відповідній гілці.Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.