Long Polling, tutorial, część 0

Zachęcony dobrym odbiorem mojego pierwszego turoriala zacząłem pracę nad kolejnym. Niestety nie udało mi się skończyć przed urlopem i straciłem nieco wątek. Dlatego zdecydowałem się dostarczyć go Wam w częściach, dzięki temu wykonując kolejne (gotowe już) części będę mógł się odnaleźć i jednocześnie mam nadzieję na wyłapanie drobnych błędów. Mam nadzieję, że Wam się spodoba.

Czym jest long pooling

Long polling jest metodą, która przy pomocy bezstanowego protokołu HTTP (opartego na zasadzie “żądań wysyłanych do serwera” ), symuluje sytuację, w której serwer wysyła zaktualizowaną informację klientowi w momencie jej aktualizacji (“server push“. W prawdzie dużymi krokami zbliżają się do nas web sockets zaimplementowane w firefozie, ale wydaje mi się, że fajnie jest zapoznać się z tą techniką (i przy okazji “podostrzyć piłę”).

Zajmiemy się dość prostym pomysłem. Kombinacja czatu i forum, w którym możemy umieszczać swoje posty i w czasie rzeczywistym, bez przeładowania strony, widzieć pojawiające się posty innych uczestników dyskusji (możesz myśleć o tym jak o okrojonym Google Wave).

Po stronie serwera wykorzystamy cakePHP, a po stronie klienta wesprze nas cudowne jQuery. Zakładam, że jesteś nieco zaznajomiony z tymi narzędziami – nie będę tutaj zamieszczał instrukcji jak skonfigurować połączenie z bazą w cakePHP itp.

Funkcjonalności w tworzonym systemie:

  • dodawanie nowego wątku
  • odpowiadanie w wątku bez przeładowania strony
  • otrzymywanie odpowiedzi innych użytkowników bez przeładowania strony

dodatkowo pamiętamy, że jako pasjonaci zaczynamy z niewielką ilością funduszy, więc chcemy aby nasza aplikacja była tak lekka dla serwera jak to możliwe (czyli przeniesiemy tyle pracy na stronę klienta ile się da).

Przygotowanie projektu

Pobierz najnowszą wersję cake’a:

$ git clone http://github.com/cakephp/cakephp.git longPolling

I stwórz bazę danych, która przechowa nasze dyskusje

CREATE TABLE `posts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  `lft` int(11) DEFAULT NULL,
  `rght` int(11) DEFAULT NULL,
  `message` text COLLATE utf8_unicode_ci NOT NULL,
  `modified` datetime NOT NULL,
  UNIQUE KEY `id` (`id`),
  KEY `parent_id` (`parent_id`),
  KEY `lft` (`lft`),
  KEY `rght` (`rght`),
  KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

Jak łatwo zauważyć będziemy wykorzystywali technikę zwaną “Nested set model“, którą implementuje Treebehavior. Dla maksymalnej prostoty wątki nie mają tytułów itd, zawiązanie wątku odbywa się po prostu przed dodanie postu, który nie jest odpowiedzią na żaden inny post.

Teraz przy pomocy narzędzia bake stwórz model, kontroler i widoki dla CRUD – będzie to podstawą dla dalszej pracy. Nie zawracaj sobie głowy walidacją czy akcjami admina – nie jest to ważne w tym ćwiczeniu. Dodaj behavior Tree do modelu Post.

Porządki

Już mamy trochę bałaganu w naszym kodzie. Widoki `add` i `edit` nawzajem się duplikują, więc usuniemy widok `add.ctp` oraz zmusimy PostsController::add() do korzystania z widoku `edit`:

//posts_controller.php 
	function add() {
		if (!empty($this->data)) {
			$this->Post->create();
			if ($this->Post->save($this->data)) {
				$this->Session->setFlash(__('The post has been saved', true));
				$this->redirect(array('action' => 'index'));
			} else {
				$this->Session->setFlash(__('The post could not be saved. Please, try again.', true));
			}
		}
		$this->render("edit");
	}

oraz, żeby zachować nieco estetyki, otoczmy kod wyświetlający link “delete” instrukcją if, żeby nie pokazywał się w przypadku dodawania nowego postu:

		<?php if(!empty($this->data["Post"]["id"])): ?>
			<li>Html->link(__('Delete', true), array('action' => 'delete', $this->Form->value('Post.id')), null, sprintf(__('Are you sure you want to delete # %s?', true), $this->Form->value('Post.id'))); ?>
		<?php endif; ?>

i jeszcze kosmetyka – usuńmy pola user_id, lft, rght, modified z formularza (są one wypełniane automatycznie).

I jeszcze jedno: na początku będziemy wybierać w formularzu posty z listy select, żeby wskazać wiadomość na którą odpowiadamy, dodaj w kontrolerze poniższą metodę i wywołaj ją w akcjach `add` oraz `edit`:

//posts_controller.php
function _getParentPosts(){
	$this->set('parents', $this->Post->find("list"));
}

Teraz możesz ręcznie dodać dyskusję… chyba, że jesteś bardzo wygodny – możesz odpalić poniższe instrukcje sql:

INSERT INTO `posts` VALUES (1,NULL,NULL,1,8,'first message in the topic.','0000-00-00 00:00:00'),
(2,1,NULL,2,5,'my very first reply to the very first message!','0000-00-00 00:00:00'),
(3,1,NULL,6,7,'I just have some opinion about first message, and will share it with you... soon.','0000-00-00 00:00:00'),
(4,2,NULL,3,4,'I think you shouldn\'t make off-topics here','0000-00-00 00:00:00');

Teraz jesteśmy gotowi do zabawy.

Share Button