cakephp comments

Google analytics tells me that I have a lot of gust on “cakephp comments” search phrase. They’re not happy because I have nothing to offer in this matter yet. The bounce rate on that phrase is above 99%.

I don’t mind that, but don’t want to leave You without any help. So I’ll leave a road mark for You:
Feature rich, customizable comments plugin

When You have this pluggin up and running in Your app – drop in back to me and read about how to make cool web 2.0 dashboard view and learn some of jQuery features.

Good luck!

Share Button

cakephp comments

Mam wielu gości, którzy wpadają na tego bloga przez frazę “cakephp comments”. Niestety lądują tu przez przypadek – piszę o cakephp i na końcu każdego postu są komentarze ;) Nic interesującego i potwierdza to bounce rate powyżej 99% :D

Jednak mimo, że osobiście nie mam nic do zaoferowania w tej kwestii – mogę pozostawić drogowskaz dla wszystkich poszukujących:
Plugin komentarzy cakePHP

Jak już podepniecie ten mechanizm w swoich systemach – wpadnijcie znów do mnie i poczytajcie o tym jak stworzyć fajny widok zbiorczy web 2.0 i poznać przy okazji możliwości jQuery.

Powodzenia!

Share Button

Jak w Cake próbujemy zrobić “prawdziwy” plugin

Oficjalnie CakePHP daje możliwość budowania pluginów, jednak sprowadza się to na razie jedynie do umożliwienia oddzielenia logiki “mini aplikacji” (którą jest plugin właśnie) od aplikacji głównej. Jednak, żeby plugin był pluginem, musi mieć możliwość łatwego plugIN oraz plugOUT naszej mini-aplikacji.

Pierwsze nasze (w firmie) podejście skutkowało “pluginem” newslettera, który był wręcz komicznie powiązany z aplikacją główną. Używał jej modeli, żeby pobrać Userów do wysyłki i nie tylko. Podłączenie i odłączenie pluginy od jakiekolwiek aplikacji oznaczało krach aplikacji w kilku miejscach i wymagało sporej zabawy z kodem. Nie tak powinno się to odbywać.

Z pluginami próbowałem bawić się przy okazji innych projektów stykałem się z tym problemem i powoli w głowie kiełkowały pomysły. Okazja aby je wypróbować nadarzyła się niedawno. Przy budowie nowego portalu potrzebowaliśmy forum. Wcześniej przy okazji dobrzemieszkaj.pl udało nam się “spiąć” phpBB z naszą aplikacją, ale okazało się to droga przez mękę. Do tego praktycznie nie było mowy o modyfikacji funkcjonalności phpBB.

Jako, że “nasze” forum ma być mniejsze (funkcjonalnie), jednak ma mieć możliwość łatwiejszego integrowania go z naszymi wszystkimi aplikacjami – rozsądnym wydało się napisanie go od zera. Jako plugin właśnie.

Jedyną zasadą jakiej wymagałem od pluginu była niezależność i maksymalna bezkolizyjność pluginy z aplikacją i innymi pluginami.

Teraz szczegóły:
1. po pierwsze plugin powinien mieć możliwość posiadania odseparowanej bazy danych. Czy to faktycznie innej, czy tylko poprzez zdefiniowanie innych prefixów. Dlatego został zdefiniowany dla niego osobna konfiguracja, oraz w ForumAppModel, po którym mają dziedziczyć modele tego pluginu wymusiliśmy korzystanie z tej konfiguracji

// /app/config/database.php
var $forum_plugin = array(
'driver' => 'mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'login',
'password' => '*******',
'database' => 'database',
'prefix' => 'forum_plugin_',
);
// /app/plugins/forum/forum_app_model.php
class ForumAppModel extends Model {
var $useDbConfig = 'forum_plugin';

var $actsAs = array("Containable");
}

W ten sposób jesteśmy bardziej zabezpieczeni przed kolizjami w bazie.

2. Wiadomo było, że nasz plugin będzie musiał korzystać z przynajmniej dwóch mechanizmów dostarczanych przez aplikację główną: Userów (logowanie, znajomi etc.) i Tagów (tematy miały być tagowane).

Postanowiłem wykorzystać koncepcję interfejsów z języka Java mimo, iż takowe w PHP nie istnieją. Od czego jednak wyobraźnia? Długo wahałem się gdzie taki interfejs miałby siedzieć – najlepszym miejscem wydał się komponent.


/**
* Interfejs User.
* Jeśli chcesz, aby forum plugin współdziałał z Twoimi klasami zarządzania użytkownikami - możesz
* tutaj ewentualnie oprogramować odpowiednie metody interfejsu. Jednak lepszym pomysłem jest podanie
* ścieżek do kontrolerów i akcji w bootstrap.php
*
*/
class IUserComponent extends Object {

function startup(&$controller){
;
}

/**
* @return int id zalogowanego użytkownika
*/
function getLoggedInUserId() {
return 1;
}

/**
* @param int $id id użytkownika
* @return string nazwa użytkownika
*/
function getUserName($id) {

}

/**
* Ma zwracać id użytkownika na podstawie jego nazwy
*
* @param string $name nazwa użytkownika
* @return mixed id użytkownika, lub false, jeśli nie istnieje żaden o takiej nazwie
*/
function getUserIdFromName($name) {
return 1;
}

/**
* Funckja ma zwracać listę z nazwami użytkowników ***podobnych*** do parametru $name
* Używana do listy autoComplete
* @param string $name
* @return array tablica użytkowników
*/
function listUsersByName($name) {
return array(1 => 'User1', 'User2', 'User3', 'User4', 'User5', 'User6', 'User7',
'User8', 'User9');
}

/**
* Funkcja pobiera listę użytkowników - przyjaciół zalogowanego użytkownika
* @return array
*/
function getUserFriends(){
return array(1=>'User 1', 2=>'User 2', 3=>'User 3', 4=>'User 4');
}

}
// oczywiście te metody muszą zostać zaimplementowane przy "spinaniu" pluginu z aplikacją główną

I od tej pory KAŻDA próba odczytu danych o użytkownikach musi przechodzić przez ten interfejs. Utrzymanie tej zasady było o tyle proste, że plugin kodowaliśmy w oderwaniu od aplikacji głównej (dopiero po jakimś czasie spróbowaliśmy ją spiąć z aplikacją, co się udało).

Jakie były plusy tego rozwiązania?

  • można pominąć brak implementacji elementów, które będą kluczowe dla działania pluginu (np User) gdyż jesteśmy schowani za interfejsem, który na razie udaje, że działa
  • przy “spinaniu” pluginu należy się co najwyżej zająć implementacją interfejsu. Najlepiej byłoby gdyby, wszystkie z metod można było wywołać przy pomocy requestAction w pluginie
  • plugin jest niezależny od aplikacji głownej – możemy go rozwijać niezaleźnie

O czym należy pamiętać? O tym, że nie tylko należy uważać, aby plugin nie “splątał” się z aplikacją główną, ale też żeby nie stało się na odwrót. Na przykład musieliśmy wyświetlić na stronie głównej najnowsze wątki. Zrobiliśmy to przez requestAction, jednak wcześniej należało wykonać test, czy plugin istnieje. Gdy zostanie usunięty – nie powinny pojawiać się błędy (a przynajmniej nie zbyt wiele ;))

Jakie są minusy rozwiązania?

  • Gdy pobiorę listę postów i chcę przy nich wyświetlić autora – dla każdego z osobna musze wywołać (przez requestAction na przykład) metodę w kontrolerze pluginu, który wywoła IUser->getUserName($id). Może to rzutować na wydajność.
  • powyższy problem można rozwiązać zapisując login usera w tablicy z postami (redundancja), ale powoduje to rozsynchronizowanie danych (przy zmianie loginu)

Jednak te problemy są mniejsze niż te, które są powodowane ścisłym powiązaniem pluginy z aplikację (wtedy po prostu przestaje był pluginem). Poza tym można by je rozwiązać przy pomocy bardziej wyszukanych mechanizmów obsługi pluginów, jednak o tym napiszę następnym razem.

Share Button