Jacek Kowalski
2014-06-11 5ab2921256e688e2f005b04bfe08f8c8bb91fd68
commit | author | age
8bd4d9 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
JK 2 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" lang="pl">
3 <head>
4 <title>Tworzenie modułów - Bot Gadu-Gadu - dev.Jacekk.info</title>
5 <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
6 <style type="text/css">
7 body {font-family: sans-serif;}
8 h3 {    padding: 5px 20px;
9     border-top: 2px solid black;
10     border-bottom: 2px solid black;
11     text-transform: uppercase;}
12 h3:before {
13     counter-increment: header-h3;
14     content: counter(header-h3) ". ";
15     counter-reset: header-h4;}
16 h4 {    padding: 5px 10px;
17     border-top: 1px solid black;
18     border-bottom: 1px solid black;}
19 h4:before {
20     counter-increment: header-h4;
21     content: counter(header-h4, lower-latin) ") ";}
22 ol#menu ol {list-style-type: lower-latin;}
23 pre {    margin-left: 20px;
24     border-left: 3px solid #666;
25     padding-left: 12px;}
26 pre.plain{border:none;}
27 pre > span:first-child {
28     display: block;
29     background: #666;
30     color: #fff;
31     padding: 5px 10px;
32     margin-left: -12px;
33     margin-bottom: 8px;}
34 code * {font-style: normal;
35     font-weight: normal;}
36 code var {color: #0000BB;}
37 code b {color: #007700;}
38 code cite {color: #DD0000;}
39 code i {color: #FF9900;}
40 .info, .warning, .example {
41     padding-left: 40px;
42     padding-top: 7px;
43     min-height: 26px;
44     background-repeat: no-repeat;}
45 .info {    background-image: url(img/info.png);}
46 .warning {background-image: url(img/warning.png);}
47 code, pre {
48     margin-top:0px;
49     padding-top:0;}
50 .example {
51     background-image: url(img/example.png);
52     margin-bottom: 0px;}
53 </style>
54 </head>
55 <body>
56 <pre class="plain">
57  ___  ___    ______    _______    __    __   __    ___    ___
58 |   \/   |  /  __  \  |   __  \  |  |  |  | |  |__ \  \  /  /
59 |  \  /  | |  |  |  | |  |  \  | |  |  |  | |  ' /  \  \/  /
60 |  |\/|  | |  |  |  | |  |   | | |  |  |  | |   /    \    /
61 |  |  |  | |  |__|  | |  |__/  | |  |__|  | |  |____  |  |
62 |__|  |__|  \______/  |_______/   \______/  |_______| |__|
6f84c6 63 Poradnik v2.1                           Tworzenie i edycja
8bd4d9 64 </pre>
JK 65
66 <h3 id="tableOfContent">Spis treści</h3>
67
68 <div id="menu">
69 </div>
70
71 <h3 id="interfaceBotModuleInit">Rejestracja modułu - interfejs BotModuleInit</h3>
72
73 <p>Należy w katalogu ./modules/ utworzyć folder o dowolnej nazwie, na przykład:</p>
74 <pre>99_NAZWAMODULU</pre>
75
76 <p class="info">Zaleca się, by nazwa folderu była postaci 00_NAZWAMODULU, gdzie 00 to cyfry umożliwiające ustawienie kolejności modułów. Jest to przydatne przy wyświetlaniu pomocy lub listy funkcji.</p>
77
78 <p>Folder ten powinien zawierać plik o nazwie init.php, zawierający klasę o dowolnej nazwie, implementującą BotModuleInit, oraz co najmniej dwie metody - register i help. Na końcu pliku powinna znajdować się konstrukcja return, zwracająca nazwę klasy:</p>
79
80 <pre>
81 <span>./modules/99_NAZWAMODULU/init.php</span><code><b>&lt;?php
82 class <var>bot_NAZWAMODULU_init</var> implements <a href="#interfaceBotModuleInit"><var>BotModuleInit</var></a>
83 {
84    function <var>register</var>() {
85    }
86
87    function <var>help</var>(<var>$params</var> = NULL) {
88    }
89 }
90
91 return <cite>'bot_NAZWAMODULU_init'</cite>;
92 ?&gt;</b></code>
93 </pre>
94
95 <p class="info">By nie powodować konfliktów nazw, zaleca się, by nazwa klasy była formatu bot_NAZWAMODULU_init, jednak nie jest to wymagane.</p>
96 <p class="warning">Błąd składniowy w pliku init.php może powodować błędy w działaniu całego bota!</p>
97 <p class="warning">Informacje zwracane przez plik inicjujący są cache'owane. Po każdej zmianie pliku init.php należy koniecznie usunąć zawartość folderu cache!</p>
98
99 <h4 id="interfaceBotModuleInit_methodRegister">Metoda register()</h4>
100
101 <p>Metoda <code><var>register</var><b>()</b></code> ma zwracać tablicę następującej postaci:</p>
102 <pre>
103 <code><b>array(</b>
104    <cite>'komenda' <b>=&gt; array(
105       array(</b>
106          'file' <b>=&gt;</b> 'komenda.php'<b>,</b>
107          'class' <b>=&gt;</b> 'bot_NAZWAMODULU_module'<b>,</b>
108          'method' <b>=&gt;</b> 'komenda1'<b>,</b>
109          'params' <b>=&gt;</b> 'parametr_do_funkcji'<b>,
110       ),
111       array(</b>
112          'file' <b>=&gt;</b> 'komenda.php'<b>,</b>
113          'class' <b>=&gt;</b> 'bot_NAZWAMODULU_module'<b>,</b>
114          'method' <b>=&gt;</b> 'komenda2'<b>,
115       ),
116    ),</b>
117    '*'<b> =&gt; array(
118       array(</b>
119          'file' <b>=&gt;</b> 'test.php'<b>,</b>
120          'class' <b>=&gt;</b> 'NAZWAMODULU_test'<b>,</b>
121          'method' <b>=&gt;</b> 'komenda_test'</cite><b>,
122       ),
123    ),
124 )</b></code>
125 </pre>
126
127 <p><code><cite>'komenda'</cite></code> to nazwa obsługiwanej przez moduł komendy. <code><cite>'*'</cite></code> oznacza, że obsługiwana może być każda wiadomość od użytkownika. <code><cite>'file'</cite></code> zawiera nazwę pliku, w którym znajduje się klasa z parametru <code><cite>'class'</cite></code>. <code><cite>'method'</cite></code> to metoda klasy, która przetwarza daną komendę. Opcjonalny parametr <code><cite>'params'</cite></code> zawiera dowolny obiekt (np. string, array), na którym można wykonać funkcję <code><a href="http://php.net/serialize"><var>serialize</var></a><b>()</b></code>, a który zostanie przekazany do wywoływanej metody. Więcej informacji o sposobie przetwarzania wiadomości od użytkownika znajduje się w kolejnym dziale: <a href="#interfaceBotModule">Komunikacja z użytkownikiem - interfejs BotModule</a></p>
128
129 <p class="info"><code><cite>'komenda'</cite></code> powinna zawierać jedynie małe litery alfabetu angielskiego. Jeżeli zawiera polskie ogonki lub wielkie litery, zostaną one automatycznie zastąpione odpowiednikami. Jeśli równocześnie istnieją indeksy zawierające np. <code><cite>'ą'</cite></code> oraz <code><cite>'a'</cite></code>, mogą one zostać połączone w dowolnej kolejności.</p>
130
131 <p class="example">Przykład - rejestrowanie komendy przyklad:</p>
132 <pre>
133 <span>./modules/99_przyklad/init.php</span><code><b>&lt;?php
134 class <var>bot_przyklad_init</var> implements <a href="#interfaceBotModuleInit"><var>BotModuleInit</var></a>
135 {
136    function <var>register</var>() {
137       return array(</b>
138          <cite>'przyklad' <b>=&gt; array(
139             array(</b>
140                'file' <b>=&gt;</b> 'przyklad.php'<b>,</b>
141                'class' <b>=&gt;</b> 'bot_przyklad_module'<b>,</b>
142                'method' <b>=&gt;</b> 'komenda_przyklad'<b>,</b>
143                'params' <b>=&gt;</b> 'parametr_do_funkcji'</cite><b>,
144             )
145          )
146       );
147    }
148
149    <i>/* Pominięto tu wymaganą metodę help().
150       Jej implementację można znaleźć poniżej. */</i>
151 }
152
153 return <cite>'bot_przyklad_init'</cite>;
154 ?&gt;</b></code>
155 </pre>
156
157 <p class="info">W dalszej części zakładamy, że tworzymy moduł obsługujący komendę przyklad.</p>
158
159 <h4 id="interfaceBotModuleInit_methodHelp">Metoda help()</h4>
160
161 <p>Metoda <code><var>help</var><b>()</b></code> przyjmuje argument <code><var>$params</var></code> - nazwę komendy, dla której ma zwrócić, za pośrednictwem <a href="classBotMsg">klasy BotMsg</a>, pomoc. Jeśli argument ten jest identyczny z <code><b>NULL</b></code>, należy zwrócić skróconą listę poleceń z krótkim wyjaśnieniem, zakończoną dwoma znakami nowej linii.</p>
162
163 <p>Jeżeli moduł nie ma pomocy lub nie obsługuje danej komendy (szczególnie dla pseudokomendy <code><cite>'*'</cite></code>), powinna zostać zwrócona wartość <code><b>FALSE</b></code></p>
164
165 <p>Jeżeli żaden moduł nie zwrócił wiadomości z pomocą, użytkownik jest informowany o braku pomocy dla danej komendy.</p>
166
167 <p class="info">Skrócona lista poleceń jest generowana tylko z tych plików init.php, które rejestrują przynajmniej jedną komendę.</p>
168
169 <p class="example">Przykład - funkcja <code><var>help</var><b>()</b></code>:</p>
170 <pre>
171 <code><b>  function <var>help</var>(<var>$params</var> = NULL) {
172       if(<var>$params</var> === NULL) {
173          return new <a href="#classBotMsg"><var>BotMsg</var></a>(<cite>'&lt;b&gt;przyklad&lt;/b&gt; &lt;i&gt;[argument]&lt;/i&gt;&lt;br /&gt;'<b>.</b>"\n"<b>.</b>
174             '   Zwraca przykładowy tekst oraz treść argumentu&lt;br /&gt;&lt;br /&gt;'</cite>);
175       }
176       else
177       {
178          return new <a href="#classBotMsg"><var>BotMsg</var></a>(<cite>'&lt;b&gt;przyklad&lt;/b&gt; &lt;i&gt;[argument]&lt;/i&gt;&lt;br /&gt;'<b>.</b>"\n"<b>.</b>
179             '   Komenda zwraca przykładowy tekst oraz treść argumentu &lt;i&gt;[argument]&lt;/i&gt; (jeśli istnieje)'</cite>);
180       }
181    }</b></code>
182 </pre>
183
184 <h4 id="interfaceBotModuleInit_example">Przykład</h4>
185 <pre>
186 <span>./modules/99_przyklad/init.php</span><code><b>&lt;?php
187 class <var>bot_przyklad_init</var> implements <var>BotModuleInit</var>
188 {
189    function <var>register</var>() {
190       return array(</b>
191          <cite>'przyklad' <b>=&gt; array(
192             array(</b>
193                'file' <b>=&gt;</b> 'przyklad.php'<b>,</b>
194                'class' <b>=&gt;</b> 'bot_przyklad_module'<b>,</b>
195                'method' <b>=&gt;</b> 'komenda_przyklad'<b>,</b>
196                'params' <b>=&gt;</b> 'parametr_do_funkcji'</cite><b>,
197             )
198          )
199       );
200    }
201    
202    function <var>help</var>(<var>$params</var> = NULL) {
203       if(<var>$params</var> === NULL) {
204          return new <a href="#classBotMsg"><var>BotMsg</var></a>(<cite>'przyklad &lt;i&gt;[argument]&lt;/i&gt;&lt;br /&gt;'<b>.</b>"\n"<b>.</b>
205             '   Zwraca przykładowy test oraz treść argumentu&lt;br /&gt;&lt;br /&gt;'</cite>);
206       }
207       else
208       {
209          return new <a href="#classBotMsg"><var>BotMsg</var></a>(<cite>'przyklad &lt;i&gt;[argument]&lt;/i&gt;&lt;br /&gt;'<b>.</b>"\n"<b>.</b>
210             '   Komenda zwraca przykładowy test oraz treść argumentu &lt;i&gt;[argument]&lt;/i&gt; (jeśli istnieje)'</cite>);
211       }
212    }
213 }
214
215 return <cite>'bot_przyklad_init'</cite>;
216 ?&gt;</b></code>
217 </pre>
218
219 <h4 id="interfaceBotModuleInit_more">Dalsze informacje</h4>
220
221 <p>Następne sekcje zawierają informacje dotyczące klas i metod, które umożliwiają przetwarzanie wiadomości od użytkownika i wysyłanie komunikatu zwrotnego.</p>
222
223 <p class="info">Jeśli moduł posiada dane, które musi przechowywać (np. słownik, tabelę kursów itp.), należy zapoznać się z sekcją <a href="#appendixDataStorage">Przechowywanie danych i ich aktualizacja</a></p>
224
225 <h3 id="classBotMessage">Informacje o użytkowniku i treść wiadomości - klasa BotMessage</h3>
226
227 <p>Wszystkie informacje związane z użytkownikiem są przekazywane jako pierwszy parametr do metody zarejestrowanej komendy pod postacią klasy potomnej BotMessage. Zawiera ona nastepujące pola:</p>
228
229 <h4 id="classBotMessage_propertyUser">Pole $user</h4>
230
231 <p>Zawiera wszystkie informacje o źródle i celu wiadomości - w postaci klasy BotUser. Zakładając, że <code><var>$msg</var></code> to nazwa zmiennej zawierającej klasę BotMessage, można uzyskać następujące informacje:</p>
232
233 <pre>
234 <code><var>$msg<b>-&gt;</b>user<b>-&gt;</b>interface</var></code>
235 </pre>
236
237 <p>Zawiera tekst: <code><cite>'Gadu-Gadu'</cite></code>, <code><cite>'IMified'</cite></code>, <code><cite>'HTTP'</cite></code> lub inny, który określa źródło wiadomości</p>
238
239 <pre>
240 <code><var>$msg<b>-&gt;</b>user<b>-&gt;</b>uid</var></code>
241 </pre>
242
243 <p>Zawiera numer użytkownika lub jego identyfikator (screen name).</p>
244
245 <pre>
246 <code><var>$msg<b>-&gt;</b>user<b>-&gt;</b>network</var></code>
247 </pre>
248
249 <p>Jeden z ciągów: <code><cite>'gadu-gadu.pl'</cite></code>, <code><cite>'jabber.imified.com'</cite></code>, <code><cite>'aim.imified.com'</cite></code>, <code><cite>'msn.imified.com'</cite></code>, <code><cite>'yahoo.imified.com'</cite></code>, <code><cite>'gtalk.imified.com'</cite></code>, <code><cite>'sms.imified.com'</cite></code> lub inny, identyfikujący sieć użytkownika.</p>
250
251 <pre>
252 <code><var>$msg<b>-&gt;</b>user<b>-&gt;</b>bot</var></code>
253 </pre>
254
255 <p>Informacja o bocie, do którego została wysłana wiadomość. Numer w przypadku Gadu-Gadu lub botkey w przypadku IMified.</p>
256
257 <pre>
258 <code><var>$msg<b>-&gt;</b>user<b>-&gt;</b>params</var></code>
259 </pre>
260
261 <p>Inne parametry. W przypadku IMified zawiera ciąg <code><cite>'public'</cite></code> lub <code><cite>'private'</cite></code>, pozwalający odróżnić źródło wiadomości na twitterze.</p>
262
263 <h4 id="classBotMessage_propertySession">Pole $session</h4>
264
265 <p>Odpowiednik klasy database z poprzedniej wersji bota. Aktualnie instancja klasy BotSession, umożliająca przechowywanie danych przypisanych do użytkownika, m.in. miasta, nazwy kina i tym podobnych.</p>
266
57117d 267 <p class="warning">Przed użyciem sesji należy ustawić nazwę klasy, dla której zmienne będą przetwarzane. Jest to odpowiednik drugiego argumentu przekazywanego do metody database::get() z pierwszych wersji bota.</p>
JK 268
8bd4d9 269 <p>Przykład użycia:</p>
JK 270
271 <pre>
57117d 272 <code>
JK 273 <i>// Ustawienie nazwy modułu. WYMAGANE!</i>
274 <var>$msg<b>-&gt;</b>session<b>-&gt;</b>setClass</var><b>(<cite>'przyklad'</cite>);</b>
275
276 <i>// Ustawienie pojedynczej wartości</i>
8bd4d9 277 <var>$msg<b>-&gt;</b>session<b>-&gt;</b>zmienna</var> <b>= <cite>'To jest test'</cite>;</b>
JK 278 <a href="http://php.net/assert"><b>assert</b></a><b>(</b><var>$msg<b>-&gt;</b>session<b>-&gt;</b>zmienna</var> <b>=== <cite>'To jest test'</cite>);</b>
279
280 <i>// Usunięcie pojedynczej wartości</i>
281 <a href="http://php.net/unset"><b>unset</b></a><b>(</b><var>$msg<b>-&gt;</b>session<b>-&gt;</b>zmienna</var><b>);</b>
282 <a href="http://php.net/assert"><b>assert</b></a><b>(</b><var>$msg<b>-&gt;</b>session<b>-&gt;</b>zmienna</var> <b>=== NULL);</b>
283
284 <i>// Usunięcie wszystkich danych</i>
285 <var>$msg<b>-&gt;</b>session<b>-&gt;</b>truncate</var><b>();</b>
286 <a href="http://php.net/assert"><b>assert</b></a><b>(</b><var>$msg<b>-&gt;</b>session<b>-&gt;</b>zmienna</var> <b>=== NULL);</b>
287
288 <i>// Dopisanie (nadpisanie) danych</i>
289 <var>$tablica</var> <b>= array(</b>
290    <cite>'zmienna' <b>=&gt;</b> 'To jest test'<b>,</b>
291    'zmienna2'</cite> <b>=&gt; new DateTime()
292 );</b>
293 <var>$msg<b>-&gt;</b>session<b>-&gt;</b>push<b>(</b>$tablica</var><b>);</b>
294
295 <a href="http://php.net/assert"><b>assert</b></a><b>(</b><var>$msg<b>-&gt;</b>session<b>-&gt;</b>zmienna</var> <b>=== <cite>'To jest test'</cite>);</b>
296 <a href="http://php.net/assert"><b>assert</b></a><b>(</b><var>$msg<b>-&gt;</b>session<b>-&gt;</b>pull<b>() ===</b> $tablica</var><b>);</b>
297
298 <i>// push() nie usuwa istniejących danych</i>
299 <var>$msg<b>-&gt;</b>session<b>-&gt;</b>zmienna3</var> <b>= <cite>'To jest test'</cite>;</b>
300 <var>$msg<b>-&gt;</b>session<b>-&gt;</b>push<b>(</b>$tablica</var><b>);</b>
301 <a href="http://php.net/assert"><b>assert</b></a><b>(</b><var>$msg<b>-&gt;</b>session<b>-&gt;</b>pull<b>() !==</b> $tablica</var><b>);</b>
302
303 <i>// Usunięcie wszystkich danych</i>
304 <var>$msg<b>-&gt;</b>session</var><b>-&gt;truncate();</b>
305 <a href="http://php.net/assert"><b>assert</b></a><b>(</b><var>$msg<b>-&gt;</b>session<b>-&gt;</b>zmienna</var> <b>=== NULL);</b></code>
306 </pre>
307
308 <h4 id="classBotMessage_propertyRawText">Pole $rawText</h4>
309
310 <p>Zawiera dane, które zostały otrzymane od API, bez żadnych zmian, z zachowanym oryginalnym formatowaniem.</p>
311
312 <pre>
313 <code><var>$msg<b>-&gt;</b>rawText</var></code>
314 </pre>
315
316 <h4 id="classBotMessage_propertyText">Pole $text</h4>
317
318 <p>Zawiera dane, które zostały otrzymane od API, wielkie litery zamienione na małe, wszystkie znaki alfabetu innego niż angielski transliterowane. Zobacz: <code><var>funcs</var><b>::</b><a href="#appendixHelpers_classFuncs_methodUtfToAscii"><var>utfToAscii</var></a><b>()</b></code></p>
319
320 <pre>
321 <code><var>$msg<b>-&gt;</b>text</var></code>
322 </pre>
323
324 <h4 id="classBotMessage_propertyCommand">Pole $command</h4>
325
326 <p>Nazwa komendy (pierwszy wyraz z <a href="#classBotMessage_propertyText">pola $text</a>).</p>
327
328 <pre>
329 <code><var>$msg<b>-&gt;</b>command</var></code>
330 </pre>
331
332 <h4 id="classBotMessage_propertyArgs">Pole $args</h4>
333
334 <p>Parametry przekazane do komendy (pozostałe wyrazy z <a href="#classBotMessage_propertyRawText">pola $rawText</a>).</p>
335
336 <pre>
337 <code><var>$msg<b>-&gt;</b>args</var></code>
338 </pre>
339
6f84c6 340 <h4 id="classBotMessage_propertyImages">Pole $images</h4>
JK 341
342 <p>Tablica obrazków (obiektów klasy BotImage) przesłanych do bota przez użytkownika.</p>
343
344 <pre>
345 <code><b>if(<a href="http://php.net/assert"><var>count</var></a>(<var>$msg</var>-&gt;<var>images</var>) &gt; <var>0</var>) {</b>
346     <i>// Do bota zostały przesłane obrazki</i>
347     
348     <i>// Pierwszy obrazek</i>
349     <var>$img <b>=</b> $msg<b>-&gt;</b>images</var><b>[<var>0</var>];</b>
350     
351     <i>// Obrazek w formie gotowej do obróbki za pomocą biblioteki GD</i>
352     <var>$gd <b>=</b> $img<b>-&gt;</b>getImage</var><b>();</b>
353     <a href="http://php.net/imagestring"><var>imagestring</var></a><b>(</b><var>$gd<b>,</b> 2<b>,</b> 0<b>,</b> 0</var><b>, <cite>'To jest tekst'</cite>,</b> <a href="http://php.net/imagecolorallocate"><var>imagecolorallocate</var></a><b>(<var>$gd<b>,</b> 255<b>,</b> 255<b>,</b> 255</var>));</b>
354     
355     <i>// Obrazek jako ciąg bajtów gotowych do zapisu:</i>
356     <var>$data <b>=</b> $img<b>-&gt;</b>getImageData</var><b>();</b>
357     <a href="http://php.net/file_put_contents"><var>file_put_contents</var></a><b>(<cite>'/tmp/obrazek.jpg'</cite>, <var>$data</var>);</b>
358 <b>}</b></code>
359 </pre>
360
8bd4d9 361 <h3 id="interfaceBotModule">Komunikacja z użytkownikiem - interfejs BotModule</h3>
JK 362
363 <p>Zgodnie z danymi zwracanymi przez <a href="#interfaceBotModuleInit_methodRegister">metodę register</a>, należy utworzyć plik zawierający klasę o podanej nazwie, implementującą BotModule, oraz odpowiednią metodę, przyjmującą dwa parametry:</p>
364
365 <pre>
366 <code><b>&lt;?php
367 class <var>bot_przyklad_module</var> implements <a href="#interfaceBotModule"><var>BotModule</var></a>
368 {
369    function <var>komenda_przyklad</var>(<var>$msg</var>, <var>$param</var> = NULL) {
370    }
371 }</b></code>
372 </pre>
373
374 <p>Po wysłaniu przez użytkownika do bota polecenia, system wywoła w kolejności moduły, które zarejestrowały otrzymaną komendę (pierwszy wyraz w wiadomości), a następnie spróbuje wykonać moduły, które zarejestrowały się jako właściwe dla wszytkich komend (indeksem tablicy zwróconej w metodzie register była <code><cite>'*'</cite></code>). Do metod zostaną przekazane dwa parametry, opisane w powyższym przykładzie jako <code><var>$msg</var></code> i <code><var>$param</var></code>. Pierwszy z nich to instancja klasa <a href="#classBotMessage">BotMessage</a>, a drugi - wartość z indeksu <code><cite>'params'</cite></code> podawanego podczas rejestracji komendy.</p>
375
376 <p>Wywołana metoda powinna zwrócić instancję <a href="#classBotMsg">klasy BotMsg</a> lub <code><b>FALSE</b></code>, jeżeli nie chce obsłużyć otrzymanej wiadomości. W drugim przypadku obsługa zostanie przekazana kolejnej metodzie/modułowi, który zarejestrował daną komendę, następnie do plików obsługujących komendę "*", a na końcu użytkownikowi zostanie wysłana informacja o nieobsługiwanym poleceniu.</p>
377
378 <p class="info">Jeśli moduł ma przechowywać dane dotyczące użytkownika, należy zapoznać się z sekcją <a href="#classBotMessage_propertySession">Klasa BotMessage - pole $session</a></p>
379
380 <pre>
381 <span>./modules/99_przyklad/przyklad.php</span><code><b>&lt;?php
382 class <var>bot_przyklad_module</var> implements <a href="#interfaceBotModule"><var>BotModule</var></a>
383 {
384    function <var>komenda_przyklad</var>(<var>$msg</var>, <var>$param</var> = NULL) {</b>
385       <var>$reply</var> <b>= new</b> <a href="#classBotMsg"><var>BotMsg</var></a><b>(<cite>'&lt;p&gt;Przykładowy moduł&lt;/p&gt;'</cite>);</b>
386       <var>$reply</var><b>-&gt;</b><a href="#classBotMsg_methodAppend"><var>append</var></a><b>(<cite>'&lt;p&gt;Twój numer/identyfikator: '</cite> .</b> <var>$msg</var><b>-&gt;</b><a href="#classBotMessage_propertyUser"><var>user</var></a><b>-&gt;</b><var>uid</var>  <b>. <cite>'&lt;br /&gt;'</cite>
387          . <cite>'Otrzymane parametry: '</cite> .</b> <var>$msg</var><b>-&gt;</b><a href="#classBotMessage_propertyArgs"><var>args</var></a>  <b>. <cite>'&lt;/p&gt;'</cite>);
388       return <var>$reply</var>;
389    }
390 }
391 ?&gt;</b></code>
392 </pre>
393
394 <h3 id="classBotMsg">Tworzenie wiadomości zwrotnej - klasa BotMsg</h3>
395
396 <p>Aby utworzyć wiadomość dla użytkownika, należy stworzyć instację klasy BotMsg, która jako opcjonalny parametr przyjmuje kod HTML, który ma zostać wysłany użytkownikowi:</p>
397
398 <pre>
399 <code><var>$reply</var> <b>= new</b> <a href="#classBotMsg"><var>BotMsg</var></a><b>();</b>
400 <i>// lub</i>
401 <var>$reply</var> <b>= new</b> <a href="#classBotMsg"><var>BotMsg</var></a><b>(<cite>'&lt;p&gt;Akapit z tekstem &lt;b&gt;pogrubionym&lt;/b&gt; i &lt;i&gt;pochylonym&lt;/i&gt;&lt;/p&gt;'</cite>);</b></code>
402 </pre>
403
404 <p class="info">W wiadomości przekonwertowanej na tekst <b>zachowywane są białe znaki</b>, za wyjątkiem znaków nowej linii!</p>
405
406 <h4 id="classBotMsg_methodAppend">Metoda append()</h4>
407
408 <p>W razie konieczności dodania większej ilości treści, należy wywołać metodę <code><var>append</var><b>()</b></code> lub <code><var>a</var><b>()</b></code> z parametrem będącym kodem HTML:</p>
409
410 <pre>
411 <code><var>$reply</var> <b>= new</b> <a href="#classBotMsg"><var>BotMsg</var></a><b>();</b>
412
413 <var>$reply</var><b>-&gt;</b><a href="#classBotMsg_methodAppend"><var>a</var></a><b>(<cite>'&lt;ol&gt;
414 &lt;li&gt;pierwszy element listy&lt;/li&gt;
415 &lt;li&gt;drugi element listy&lt;/li&gt;
416 &lt;/ol&gt;'</cite>);</b>
417
418 <var>$reply</var><b>-&gt;</b><a href="#classBotMsg_methodAppend"><var>append</var></a><b>(<cite>'&lt;p&gt;Kolejny akapit&lt;/p&gt;'</cite>);</b></code>
419 </pre>
420
421 <p class="warning">Zaleca się, by dodawany kod nie był "urwany", tzn. wszystkie tagi winny być poprawnie otwarte i zamknięte we wstawianym HTML-u. W przyszłości takie błędy mogą powodować odrzucenie dodawanej treści.</p>
422
423 <h4 id="classBotMsg_appendixImage">Dodawanie obrazków</h4>
424
425 <p>Aby dodać obrazek należy do kodu HTML dodać tag img, z atrybutem src zawierającym ścieżkę do obrazka względem głównego katalogu bota lub bezwzględną ścieżkę dostępu do niego:</p>
426
427 <pre>
428 <code><var>$reply</var><b>-&gt;</b><a href="#classBotMsg_methodAppend"><var>a</var></a><b>(<cite>'&lt;p&gt;Tu będzie obrazek: &lt;img src="data/przyklad/obrazek.png" /&gt;&lt;/p&gt;'</cite>);</b></code>
429 </pre>
430
431 <p class="warning">Gadu-Gadu nie obsługuje więcej niż jednego obrazka w wiadomości.</p>
432
433 <h4 id="classBotMsg_appendixTags">Wspierane tagi HTML</h4>
434
435 <p>Wspierane tagi HTML:</p>
436
437 <ul>
438 <li>a (tylko atrybut href)</li>
439 <li>b</li>
440 <li>br</li>
441 <li>h1</li>
442 <li>h2</li>
443 <li>h3</li>
444 <li>i</li>
445 <li>img (tylko atrybut src)</li>
446 <li>li</li>
447 <li>ol (także atrybut start)</li>
448 <li>p</li>
449 <li>span</li>
450 <li>strong</li>
451 <li>sub</li>
452 <li>sup</li>
453 <li>u</li>
454 <li>ul</li>
455 </ul>
456
457 <p>Wspierane atrybuty:</p>
458
459 <ul>
460 <li>color (tylko w formacie: #ABC lub #AABBCC)</li>
461 <li>style</li>
462 </ul>
463
464 <h3 id="appendixHelpers">Funkcje pomocnicze</h3>
465
466 <p>Poniższe klasy zawierają funkcje często używane w modułach.</p>
467
468 <h4 id="appendixHelpers_classCalendar_methodParseDate">calendar::parse_date()</h4>
469
470 <p>Metoda <code><var>parse_date</var></code> klasy <code><var>calendar</var></code> jest zdefiniowana następująco:</p>
471
472 <pre>
473 <code><b>static function</b> <a href="#appendixHelpers_classCalendar_methodParseDate"><var>parse_date</var></a><b>(</b><var>$date</var><b>);</b></code>
474 </pre>
475
476 <p>Przetwarza ona tekst <code><var>$date</var></code> (np. <code><cite>'wczoraj'</cite></code>, <code><cite>'jutro'</cite></code>, ale także <code><cite>'1 stycznia 2000'</cite></code>) na uniksowy znacznik czasu, który zwraca.</p>
477
478 <p class="example">Przykład:</p>
479 <pre>
480 <code><var>$data</var> <b>=</b> <a href="#appendixHelpers_classCalendar_methodParseDate"><var>calendar</var><b>::</b><var>parse_date</var></a><b>(</b><cite>'29 stycznia 2009'</cite><b>);</b>
481 <var>$wzor</var> <b>=</b> <a href="http://php.net/mktime"><var>mktime</var></a><b>(</b><var>0</var><b>,</b> <var>0</var><b>,</b> <var>0</var><b>,</b> <var>1</var><b>,</b> <var>29</var><b>,</b> <var>2009</var><b>);</b>
482 <a href="http://php.net/assert"><b>assert</b></a><b>(</b><var>$data</var> <b>==</b> <var>$wzor</var><b>);</b></code>
483 </pre>
484
485 <h4 id="appendixHelpers_classFuncs_methodUtfToAscii">funcs::utfToAscii()</h4>
486
487 <p>Metoda <code><var>utfToAscii</var></code> klasy <code><var>funcs</var></code> jest zdefiniowana następująco:</p>
488
489 <pre>
490 <code><b>static function</b> <a href="#appendixHelpers_classFuncs_methodUtfToAscii"><var>utfToAscii</var></a><b>(</b><var>$utf</var><b>);</b></code>
491 </pre>
492
493 <p>Polskie znaki w zmiennej <code><var>$utf</var></code> zamienia w litery alfabetu angielskiego (ó => o, ź => z itd.), wykonuje na tekście <code><a href="http://php.net/strtolower"><var>strtolower</var></a><b>()</b></code> oraz <code><a href="http://php.net/trim"><var>trim</var></a><b>()</b></code>, po czym zwraca tak zmodyfikowaną treść.</p>
494
495 <h3 id="appendixDataStorage">Przechowywanie danych i ich aktualizacja</h3>
496
497 <p>Jeśli istnieje potrzeba okresowego aktualizowania danych (np. kursów walut) można użyć do tego przygotowanego specjalnie dla tego bota narzędzia.</p>
498
499 <p>W folderze /data/(nazwa modułu)/ należy utworzyć plik crontab, zgodny ze <a href="http://pl.wikipedia.org/wiki/Crontab">składnią crontaba</a>.</p>
500
501 <p class="example">Przykład pliku crontab:</p>
502 <pre>
503 <code><i># To jest komentarz - znak # musi być pierwszym znakiem w linijce!
504
505 # Uruchamiaj się codziennie, co dwie godziny, między północą a dwudziestą.</i>
506 <var>0 0</var><b>-</b><var>20</var><b>/</b><var>2</var> <b>* *   *</b>  <cite>co_dwie_godziny.php</cite>
507 <i># Uruchamiaj się o 4:00 w każdą niedzielę</i>
508 <var>0      4</var> <b>* *</b>   <var>0</var>  <cite>niedziela.php</cite>
509 <i># Uruchamiaj się w każdy poniedziałek i środę o 10:00</i>
510 <var>0     10</var> <b>* *</b> <var>1</var><b>,</b><var>3</var>  <cite>pon_sr_10.php</cite></code>
511 </pre>
512
513 <p class="warning"> Pierwsze pole (minuty) jest pomijane, tj. nie można uruchamiać programu częsciej niż raz na godzinę!</p>
514 <p class="warning"> W pole 6 należy, zamiast pełnej komendy, wpisać jednynie nazwę pliku z rozszerzeniem .php, znajdującego się w katalogu z plikiem crontab (lub względną ścieżkę do niego).</p>
515
516 <script type="text/javascript">
517 // <![CDATA[
518 function generateToc() {
519     var menu = document.createElement('ol');
520     document.getElementById('menu').appendChild(menu);
521     var elems = document.querySelectorAll('h3,h4');
522     var now = 3;
523     
524     for(var i=0; i<elems.length; i++) {
525         if(elems[i].id == '') {
526             continue;
527         }
528         
529         var level = parseInt(elems[i].tagName.slice(1));
530         
531         if(level < now) {
532             while(level < now) {
533                 menu = menu.parentNode.parentNode;
534                 now--;
535             }
536         }
537         else if(level > now) {
538             while(level > now) {
539                 if(menu.lastChild) {
540                     ol = document.createElement('ol');
541                     menu.lastChild.appendChild(ol);
542                     menu = ol;
543                 }
544                 else
545                 {
546                     li = document.createElement('li');
547                     ol = document.createElement('ol');
548                     li.appendChild(ol);
549                     menu.appendChild(li);
550                     menu = ol;
551                 }
552                 
553                 now++;
554             }
555         }
556         
557         var li = document.createElement('li');
558         var a = document.createElement('a');
559         a.href = '#'+elems[i].id;
560         a.appendChild(document.createTextNode(elems[i].textContent));
561         li.appendChild(a);
562         menu.appendChild(li);
563     }
564 }
565
566 generateToc();
567 // ]]>
568 </script>
569
570 </body>
571 </html>