Poniżej jest umieszczana automatycznie treść podstrony wiki_items znajdującej się w namespace projektu. Proszę ją utworzyć i traktować jako stronę startową - tam umieszczamy linki do poszczególnych podstron, które też mają się znajdować w projekcie, np. analiza_wymagan. W namespace mogą też Państwo umieszczać pliki (obrazki, diagramy, archiwa) linkowane na stronie danego projektu. Proszę usunąć ten akapit po zapoznaniu się z jego treścią.
Celem projektu jest stworzenie otwartej bazy produktów konsumenckich. Baza ta będzie tworzona przez internautów za pośrednictwem interfejsu WWW. Serwis będzie stworzony za zasadzie Wiki, co oznacze, że użytkownicy będą mieli możliwość edycji, dodawania nowych i przeglądania poprzednich wersji stron.
Baza będzie miała charakter społecznościowy dzięki integracji z systemem Facebook. W rezultacjie platforma Wiki Items będzie dysponowała informacjami o popularności danego produktu.
Ponadto, system będzie udostępniał zawartość bazy danych poprzez interfejs programistyczny (API) zainteresowanym zewnętrznym systemom (np. sklepom internetowym).
Systemy podobne do projektowanego obejmują serwisy pozwalające na komentowanie produktów (cokupic.pl, ceneo.pl). Planowane wiki różni się od istniejących rozwiązań przede wszystkim dlatego, że wszelkie zmiany dotyczące danego artykułu będą poddawane głosowaniu użytkowników. Baza danych o produktach nie jest w wymienionych serwisach udostępniona, możliwości jej poprawiania przez użytkowników są ograniczone. Ponadto, żaden z istniejących systemów nie posiada „czynnika społecznościowego”.
Innowacyjność systemu polega na udostępnieniu platformy, która będzie wykorzystywana przez firmy i instytucje związane z handlem w internecie w celu lepszego funkcjonowania na rynku. Ważnym elementem platformy jest integracja z Facebookiem, dzięki której wszyscy zainteresowani (sprzedawcy i producenci produktów) zyskają możliwość śledzenia preferencji klientów na skalę całego rynku, jak również interakcję z docelową grupą klientów. Klienci uzyskają usystematyzowaną wiedzę na temat produktów.
Na podstawie doświadczeń teamu projektowego, oraz przeprowadzonego wywiadu wśród znajomych można stwierdzić, że konsumentom brakuje usystematyzowanej, wiarygodnej bazy wiedzy na temat produktów, przy użyciu której mogliby dokonywać świadomych i udanych zakupów. Również sprzedawcy i producenci arytkułów wynieśliby profity z obserwowania serwisu, gdyż mogliby odpowiadać na istniejące zapotrzebowanie klientów oraz wprowadzać innowacje do swoich produktów. Wiedza dotycząca ilości osób które polubiły dany produkt jest nieoceniona dla każdego przedsiębiorcy produkującego towar danej kategorii.
Celem projektu jest stworzenie otwartej bazy produktów konsumenckich dostępnej dla użytkowników za pośrednictwem wiki. Każdy zarejestrowany użytkownik będzie mógł utworzyć nową lub zedytować bieżącą stronę interesującego go produktu. Jeżeli bieżąca wersja produktu zostanie zedytowana przez użytkownika, zmiana taka musi być zatwierdzona poprzez głosowanie pozostałych internautów- pozwoli to na zatwierdzenie prawdziwych, niekomercyjnych treści dotyczących artykułu. W przeciwnym wypadku strona nie jest podmieniana i obowiązuje jej stara wersja.
Jednocześnie, baza informacji o produktach będzie miała charakter społecznościowy, dzięki integracji z systemem Facebook. Na stronie wiki zostanie umieszczony przycisk „Lubię to”, co pozwoli na ocenę przeglądanych produktów. Informacja o ilości osób, które polubiły dany produkt będzie przechowywana w bazie danych.
Baza danych będzie przechowywać wszystkie poprzednie wersje stron produktów, dzięki czemu użytkownicy będą mogli w każdej chwili prześledzić zmiany dokonane na stronach. Opinie na temat artykułów będą dostępne w różnych językach, przy czym w każdym języku strona będzie tworzona osobno (brak powiązań oprócz przełączania między stronami w różnych językach). Stworzenie oraz zatwierdzenie edycji strony będzie odbywać się w każdym z języków z osobna, przez co w każdym języku bieżąca strona może wyglądać zupełnie inaczej (informacje na tych stronach mogą od siebie odbiegać).
Dla zewnętrzych systemów będzie udostępniony interfejs programistyczny, dzięki któremu na stronach sklepów internetowych będzie można korzystać z opisu produktów na wiki oraz wiadomości dotyczących popularności danego artykułu (ilość osób lubiących dany towar na Facebooku).
Produkty będą wyświetlane na stronie w hierarchicznym porządku, każdy artykuł będzie posiadał swoją kategorię (nadkategorię) oraz zestaw atrybutów edytowanych przez użytkowników, które go specyfikują.
Aktorzy: Wiki user
Zakres: Platforma Wiki Items
Udziałowcy i ich cele: Użytkownik chce znaleźć interesujący go produkt.
Serwis potrzebuje uzyskać nazwę danego produktu, można zawęzić kategorię lub ograniczyć wyszukiwanie towarów poprzez podanie ich atrybutów (wielkość, kolor itp.)
Zdarzenie wyzwalające (trigger):
Użytkownik wybiera opcję wyszukiwania na stronie Wiki Items
Warunki wstępne: brak
Warunki końcowe dla sukcesu: bieżąca strona interesującego użytkownika produktu zostanie wyświetlona
Warunki końcowe dla niepowodzenia: produkt nie istnieje w bazie, serwis zaproponuje użytkownikowi utworzenie nowej strony produktu
Scenariusz główny:
1. Serwis wyświetla formularz wyszukiwania produktu
2. Użytkownik wprowadza dane
3. System wyszukuje produkty spełniające kryteria użytkownika
4. System prezentuje użytkownikowi znalezione produkty
5. Użytkownik przechodzi do strony produktu poprzez kliknięcie wybranego linku
Aktorzy: Wiki user
Zakres: Platforma Wiki Items
Udziałowcy i ich cele: Użytkownik chce przeglądnąć historię tworzenia strony produktu
Zdarzenie wyzwalające (trigger):
Użytkownik przechodzi do strony interesującego go produktu (używając wyszukiwarki lub przechodząc do niej z widoku kategorii)
Warunki wstępne: brak
Warunki końcowe dla sukcesu: historia strony produktu zostanie wyświetlona
Warunki końcowe dla niepowodzenia: brak
Scenariusz główny:
1. Użytkownik wybiera opcję przeglądania historii strony
2. System przekierowuje użytkownika do historii strony
Aktorzy: Wiki user
Zakres: Platforma Wiki Items
Udziałowcy i ich cele: Użytkownik chce edytować stronę produktu
Pozostali użytkownicy mają możliwość głosowania na nową wersję strony.
Zdarzenie wyzwalające (trigger):
Użytkownik przechodzi do strony interesującego go produktu (używając wyszukiwarki lub przechodząc do niej z widoku kategorii)
Warunki wstępne: użytkownik jest zalogowany
Warunki końcowe dla sukcesu: zedytowana strona zostanie zatwierdzona jako bieżąca strona produktu
Warunki końcowe dla niepowodzenia: użytkownik nie zatwierdzi edycji strony lub z edycji zrezygnuje lub pozostali internauci nie zatwierdzą zmian w głosowaniu, co spowoduje odrzucenie nowej wersji strony.
Scenariusz główny:
1. Użytkownik wybiera opcję edycji strony
2. System przekierowuje użytkownika do edycji
3. Użytkownik edytuje stronę
4. Użytkownik zatwierdza zmiany dokonane na stronie
5. System umożliwia głosowanie na nową stronę użytkownikom platformy
6. Internauci akceptują zmiany dokonane przez użytkownika (poprzez głosowanie)
Scenariusz alternatywny 1:
4.a. Użytkownik zrezygnuje z edycji strony
Scenariusz alternatywny 2:
6.a. Internauci nie akceptują zmian dokonanych przez użytkownika
Aktorzy: Wiki user
Zakres: Platforma Wiki Items
Udziałowcy i ich cele: Użytkownik chce polubić dany produkt (Facebook)
Zdarzenie wyzwalające (trigger):
Użytkownik przechodzi do strony interesującego go produktu (używając wyszukiwarki lub przechodząc do niej z widoku kategorii)
Warunki wstępne: użytkownik musi być zalogowany na swoim koncie na Facebooku
Warunki końcowe dla sukcesu: produkt zostanie polubiony
Warunki końcowe dla niepowodzenia: brak
Scenariusz główny:
1. Użytkownik klika opcję „Lubię to” na stronie produktu.
Głosowanie na wprowadzone zmiany
Aktorzy: Wiki user
Zakres: Platforma Wiki Items
Udziałowcy i ich cele: Użytkownik chce zagłosować na nową wersję strony produktu
Zdarzenie wyzwalające (trigger):
Użytkownik przechodzi do strony interesującego go produktu (używając wyszukiwarki lub przechodząc do niej z widoku kategorii)
Warunki wstępne: użytkownik musi być zalogowany na platformie
Warunki końcowe dla sukcesu: głos dla danej wersji zostanie dodany do bazy
Warunki końcowe dla niepowodzenia: brak
Scenariusz główny:
1. Użytkownik przechodzi na nową wersję strony produktu.
2. Użytkownik klika opcję „Plus” na zedytowanej stronie produktu.
Aktorzy: API user
Zakres: interfejs programistyczny (API)
Udziałowcy i ich cele: Użytkownik chce pobrać informacje na temat interesującego go produktu
Zdarzenie wyzwalające (trigger):
Użytkownik wysyła zapytanie do bazy danych produktu
Warunki wstępne: brak
Warunki końcowe dla sukcesu: dane o produkcie zostaną przesłane do użytkownika
Warunki końcowe dla niepowodzenia: brak
Scenariusz główny:
1. Użytkownik formułuje zapytanie do bazy danych (XML).
2. Baza danych wysyła informacje o produkcie do klienta API.
Liście poniższego drzewa.
Wszystkie tabeli w bazie danych spełniają warunku pierwszej postaci normalnej 1NF, gdyż każda z nich:
Relacja jest w drugiej postaci normalnej wtedy i tylko wtedy gdy jest w pierwszej postaci normalnej i każda kolumna zależy funkcyjnie od całego klucza głównego (a nie np. od części klucza).
W pierwszej kolejności można sprawdzić, czy każda kolumna zależy od klucza prostego (całego klucza dla danej tabeli). Ten warunek spełniają tabele: categories, items, properties, property_groups, property_values, revisions, users
Kolumny w tabelach posiadających klucze złożone (owner_id, lang, revision_id) zależą funkcyjnie od całego klucza głównego. Na przykład każda z kolumn w tabeli category_data zależy od id kategorii (owner_id), języka (lang) oraz wersji (revision_id). Do tabel spełniających ten warunek należą: category_data, item_data, property_data, property_group_data, property_value_data
Tabela revision_ratings również jest w drugiej postaci normalnej.
Baza danych jest w trzeciej postaci normalnej 3NF, gdy jest w 2NF oraz wszystkie niekluczowe pola zależą tylko od atrybutów kluczowych (nie ma przechodnich zależności).
W szczególności dla tabel *_data, atrybut name lub value znajdujące się w każdej z nich, tyczy się danego typu (np. kategorii) i zależy tylko od klucza głównego. W tabeli categories atrybuty opisują położnie kategorii w jednym z drzew (podgrup) kategorii i zależą również tylko od klucza, jakim jest id kategorii. Tabele items, properies, property_groups, property_values mają podobną strukturę, posiadają atrybuty będące kluczami głównymi i obcymi. Są to pomocnicze tabele do tworzenia w bazie danych relacji wiele do wielu. Tabela revisions posiada niekluczowe atrybuty: rev_no, is_head oraz user_id (FK), które w kolejności oznaczają numer wersji, oznaczenie, czy dana wersja jest aktualna oraz id użytkownika, który dokonał zmian w stosunku do poprzedniej wersji. Wszystkie te kolumny zależą tylko od klucza głównego. Tabela users posiada dane charakterystyczne dla użytkownika o podanym id. W tabeli ratings atrybut rating zależy w całości od klucza głównego, jakim jest numer wersji i id użytkownika.
Stworzona baza danych jest w trzeciej postaci normalnej 3NF.
Serwis WikiItems używa biblioteki Doctrine do komunikacji z bazą danych. Z tego powodu jako twórcy strony internetowej nie jesteśmy zmuszeni do tworzenia zapytań SQL, gdyż są one generowane z kodu PHP. W projekcie zastosowano mapowanie obiektowo-relacyjne. Przykładowe zapytania do bazy danych są przedstawione i opisane poniżej:
Kod PHP:
query = Doctrine_Query::create()
→from('Model_Item i')
→leftJoin('i.Category c')
→where('i.category_id = ? OR (c.root_id = ? AND i.category_id BETWEEN ? AND ?)', array(
category→getId(),
category→getRootId(),
category→getLeftId(),
category→getRightId()
));
Wygenerowane zapytanie:
SELECT i.id, i.category_id, i.created_at, i.updated_at, c.id, c.root_id, c.lft, c.rgt, c.level, c.created_at, c.updated_at FROM items i LEFT JOIN categories c ON i.category_id = c.id WHERE (i.category_id = ? OR (c.root_id = ? AND i.category_id BETWEEN ? AND ?))
Zapytanie odnajduje wszystkie produkty, które należą do wybranej kategorii, lub podkategorii tej kategorii.
Kod PHP:
query = Doctrine_Query::create()
→from('Model_PropertyGroup pg')
→leftJoin('pg.Category c')
→where('c.root_id = ?', root→getId())
→andWhere('c.id BETWEEN ? AND ?', array(
root→getLeftId(),
root→getRightId()
))
→andWhere('c.level < ? OR c.id = ?', array(
category→getLevel(),
category→getId()
));
Wygenerowane zapytanie:
SELECT p.id, p.category_id, p.created_at, p.updated_at, c.id, c.root_id, c.lft, c.rgt, c.level, c.created_at, c.updated_at FROM property_groups p LEFT JOIN categories c ON p.category_id = c.id WHERE (c.root_id = ? AND c.id BETWEEN ? AND ? AND (c.level < ? OR c.id = ?))
Odnajduje PropertyGroups, czyli grupy właściwości/atrybutów produktów należących do wybranej kategorii. Do grupy właściwości może należeć kilka konkretnych właściwości, którym można przypisywać wartości w tabeli property_value_data. Przykładowo grupą może być rozmiar, atrybuty należące do grupy to szerokość i wysokość, natomiast ich wartości mogą być wyrażone w calach.
Wersja Alpha: http://wikiitems.org
Implementacja bazy danych została przeprowadzona zgodnie ze schematem opracowanym na etapie projektowania aplikacji. Pełny schemat bazy danych dostępny jest w formatach SQL: schema.sql oraz YAML: schema.yml
Zaprojektowana baza danych okazała się sprawiać pewne trudności, które można podzielić na trzy kategorie:
- problemy ze znalezieniem systemu ORM, który byłby w stanie obsługiwać zaprojektowany schemat; przykładowy problem: atrybut będący częścią klucza głównego jest jednocześnie kluczem obcym - większość tego rodzaju trudności została rozwiązana poprzez dopasowanie schematu bazy danych do możliwości systemu ORM.
- problemy z wydajnością systemu ORM; tutaj na szczególną uwagę zasługuje Doctrine, który okazał się prezentować wydajność zbliżoną do biblioteki Hibernate (Java), co jest wynikiem unikatowym, biorąc pod uwagę, że jest napisany w całości w języku PHP. Doctrine jest w stanie odczytać z bazy danych kilka powiązanych obiektów przy użyciu jednego zapytania (używając złączeń).
- problemy z możliwościami silnika bazy danych; przykładowo: aby odczytać listę produktów należących do danej kategorii (oraz kategorii podrzędnych) wymagane są funkcje operujące na strukturach drzewiastych (drzewo kategorii). Tego rodzaju funkcje dostępne są bardzo niewielu systemach baz danych (np. Oracle). Tutaj z odsieczą przychodzi (po raz kolejny) biblioteka Doctrine, oferując mechanizm tzw. behaviours (zachowań) - danej encji można przypisać zachowanie, np: Timestampable lub NestedSet. Zastosowanie zachowania NestedSet w stosunku do encji Category pozwaliło na operowanie na strukturze drzewiastej z logiką przeniesioną ze strony bazy danych, na stronę PHP (przy znikomej utracie wydajności!)
Poniżej przedstawione są formularze służące do wprowadzania danych. Ze względu na zastosowanie mapowania obiektowo-relacyjnego nie zostaną przedstawione zapytania SQL realizujące wprowadzenie odpowiednich danych do bazy. Dokładniejszy opis tego mechanizmu znajduje się w sekcji: Projektowanie Operacji Na Danych
Rejestracja użytkownika
Logowanie użytkownika
Dodawanie kategorii
Szybkie wyszukiwanie
Dodawanie produktu
Poszczególne pola formularza generowane są w zależności od atrybutów i grup atrybutów cechujących produkty w danej kategorii.
Poniżej przedstawione są wykorzystywane w aplikacji widoki umożliwiające prezentację danych.
Drzewo kategorii
Lista produktów w kategorii
Na przykładzie kategorii „Cell Phones”:
Widok atrybutów kategorii
Na przykładzie kategorii „Cell Phones”„
Widok produktu
Na przykładzie produktu „iPhone 4”:
Wykorzystana w projekcie biblioteka Doctrine zapewniająca mapowanie obiektowo-relacyjne, realizuje za Nas wszelkie operacje potrzebne do obsługi bazy danych.
Uruchomienie aplikacji oraz jej testowanie odbyło się dwuetapowo. Pierwszym etapem było uruchomienie aplikacji w lokalnym środowisku. Ze względu na stricte internetowy charakter aplikacji, testy przeprowadzono z wykorzystaniem narzędzia Selenium umożliwiającego przygotowywanie automatycznych testów dla aplikacji internetowych. Po pozytywnym przejściu tych testów, aplikacja została uruchomiona na zewnętrznym serwerze www, oraz udostępniona w sieci internet pod adresem: www.wikiitems.org.
Do poprawnego uruchomienia aplikacji nie są wymagane żadne dane początkowe, jedynie poprawnie zaimportowany schemat bazy.
Wprowadzanie danych odbywa się ręcznie, poprzez formularze dostępne na stronie projektu.
Wymagania:
- serwer WWW (Apache)
- PHP 5.3+
- Zend Framework 1.11.4+
- Doctrine 1.2
Konfiguracja Apache:
- DocumentRoot należy ustawić na katalog public_html
- należy ustawić opcję: AllowOverride All
- należy upewnić się, że włączone są moduły: php5_module, rewrite_module
Konfiguracja PHP:
- należy upewnić się, że włączone są moduły: php_soap, php_pdo_mysql (lub analogiczny, w zależności od używanej bazy danych)
- należy ustawić opcję: short_open_tag = On
- należy ustawić opcję: soap.wsdl_cache_enabled = 0 (lub 1, w przypadku gdy serwer będzie używany tylko na produkcji)
Konfiguracja projektu:
- ścieżka do biblioteki Zend Framework - w pliku public_html/index.php ustawiany jest include_path (funkcja set_include_path); należy zadbać by była tam aktualna ścieżka do biblioteki Zend Framework (/library) na danym serwerze
- ścieżka do biblioteki Doctrine - j/w
- baza danych - ustawienia w pliku /application/configs/application.ini (resources.doctrine.dsn)
- konto SMTP - ustawienia w pliku /application/configs/application.ini (resources.mail.*)
- ustawienia aplikacji Facebook (Appid, Key, Secret) - ustawienia w pliku /application/configs/application.ini (resources.facebook.*)
Konfiguracja bazy danych:
- w katalogu /public_html należy uruchomić: php doctrine.php build-all-reload
Wikiitems jest z założenia aplikacją kierowaną do ogólnoświatowej społeczności, stąd też przeprowadzanie szkoleń dla użytkowników mija się z celem. Interfejs aplikacji został maksymalnie uproszczony, zaprojektowano go tak, by był intuicyjny i nie sprawiał problemów nawet mniej doświadczonym internautom. Dzięki temu samodzielne nauczenie się obsługi aplikacji zajmuje zaledwie kilka minut.
Od strony technicznej, zapewnienie działania systemu po wdrożeniu ogranicza się do utrzymywania działania serwera www oraz serwera baz danych. Z merytorycznej strony, aplikacja opiera się o ideę społecznościowej bazy danych, toteż jej zawartość moderowana i administrowane jest przez samych użytkowników, którzy wzajemnie kontrolują wprowadzane przez siebie zmiany.
Obecnie aplikacja znajduje się w fazie Beta. Administratorzy w szczególny sposób nadzorują działanie aplikacji. Użytkownikom został udostępniony Bug Tracking System (Mantis) w celu zgłaszania ewentualnych błędów lub sugestii.
Aplikacja została zbudowana starannie, z troską o bezpieczeństwo, wydajność oraz możliwość wprowadzania dalszych modyfikacji. Tym niemniej, docelowo system przeznaczony jest do obsługi znacznej ilości żądań i prawdopodobnie konieczne będą znaczne modyfikacje (w przypadku sukcesu projektu!) mające na celu poprawienie wydajności.
Aplikacja - jak uważamy - posiada spory potencjał i może być rozbudowywana o nowe funkcjonalności. Oto niektóre z pomysłów:
- dodanie możliwości komentowania/oceniania produktów
- dodanie obsługi zdjęć produktów (potencjalne problemy natury prawnej)
- zbudowanie prostej aplikacji na Facebook'u, tak aby możliwe było wyszukanie produktu bezpośrednio w wyszukiwarce FB.
- integracja z porównywarkami cen (możliwość przeniesienia użytkownika ze strony produktu do sklepu internetowego).
- zbudowanie wtyczek do popularnych silników sklepów internetowych, tak aby dane techniczne towarów mogły być pobierane z aplikacji WikiItems (obecnie, sklepy internetowe niejednokrotnie kupują wspomniane dane)
- rozbudowa integracji z Facebook (zależne od rozbudowy FB API)
- integracja z różnorodnymi systemami e-commerce, również budowanymi w przyszłości
Jednym z najistotniejszych doświadczeń związanych z projektowaniem i implementacją aplikacji WikiItems jest doświadczenie wynikające z realizacji aplikacji na podstawie wcześniej przygotowanej dokumentacji. Podejście takie, choć rzadko stosowane przez studentów daje możliwość wyeliminowania wielu błędów jeszcze przed rozpoczęciem implementacji.
Warto wspomnieć również o mechanizmie mapowania relacyjno-obiektowego, zapewnianym w Naszym projekcie przez bibliotekę Doctrine. Zapoznanie się z tym narzędziem znacznie ułatwiającym pisanie aplikacji wykorzystujących relacyjne bazy danych, zwłaszcza te, o dość złożonej strukturze, a za taką można uznać wykorzystywaną w projekcie bazę, jest bardzo pozytywnym doświadczeniem.
Wśród wykorzystanych narzędzi znalazło się również oprogramowanie Selenium. Umożliwiające przeprowadzanie automatycznych testów, z wykorzystaniem pluginu do przeglądarki Firefox. Narzędzie to pozwala m.in. na nagranie akcji użytkownika, a następnie odtworzenie ich, np. ze zmienionymi parametrami. Dzięki temu dość łatwo analizować błędy które mogą pojawiać się w trakcie implementacji kolejnych elementów interfejsu bądź samego silnika strony. Możliwości Selenium są oczywiście o wiele większe, dzięki narzędziu „Remote Control Server” można przeprowadzać automatyczne testy z wykorzystaniem dowolnej przeglądarki, jest to niezmiernie pomocne w przypadku testowania poprawności wyświetlania strony w różnych konfiguracjach. Funkcjonalność ta nie została jednak wykorzystana w projekcie.
W kwestii używanych technologii należy nadmienić, że PHP sprawdza się bardzo dobrze, głównie za sprawą bardzo dobrych bibliotek (Zend Framework, Doctrine). Tym niemniej, w stosunku to programowania w języku JAVA napotkaliśmy na pewnie niedogodności związane z dbaniem o jakość produktu. Wynika to z faktu, że PHP jest językiem interpretowanym oraz z dynamiczną typizacją - wiele błędów nie może zostać wykrytych na etapie budowania.