Писати додаткові модулі для Ubilling дуже просто, розгляньмо процес написання найпростішого модуля на прикладі модуля, що показує всіх користувачів з їхніми ПІБ та адресами у вигляді гарної сортувальної таблички.
Типовий модуль Ubilling розміщується в окремому підкаталозі /modules/general/ і складається з двох файлів: index.php і module.php. Перший із них є власне модулем із його виконуваним кодом, другий же - описом модуля для вбудованого диспатчера. Давайте припустимо, що наш модуль називатиметься samplemod і таким чином складатиметься з двох файлів:
Давайте детально розберемо що-ж знаходиться в цих двох містичних файликах.
<?php $this->registerModule($module, 'main', 'Sample module', 'Sample developer', array('SAMPLE' => __('right for access sample module'))); ?>
Містить у собі стандартний набір, який описує те, що модуль має клас main (тобто може розміщуватися в центральному блоці контенту за замовчуванням), зветься Sample module, написаний розробником на ім'я Sample developer і під час свого довантаження породжує право SAMPLE, за яким згодом ми розмежовуватимемо доступ до цього модуля. Зверніть увагу на конструкцію
__('Рядок англійською')
використану в цьому прикладі в ролі опису права на модуль. Функція повертатиме локалізований рядок відносно поточної мови, якщо він знайдений у словниковому файлі. Власне локалізація в Ubilling є подібною до gettext.
Все, з файлом опису модуля розібралися, поїхали далі.
<?php // перевіряємо чи має користувач права на користування цим модулем if (cfr('SAMPLE')) { //робимо запит до БД з метою отримати логіни всіх користувачів $query="SELECT `login`,`IP` from `users`"; $alllogins=simple_queryall($query); //отримуємо масиви всіх П.І.Б. користувачів та їхніх адрес $allrealnames=zb_UserGetAllRealnames(); $alladdress=zb_AddressGetFulladdresslist(); //перевіряємо, чи є взагалі у нас користувачі if (!empty ($alllogins)) { //Збираємо заголовок таблички для виведення $tablecells=wf_TableCell(__('Login')); $tablecells.=wf_TableCell(__('IP')); $tablecells.=wf_TableCell(__('Real Name')); $tablecells.=wf_TableCell(__('Address')); $tablerows=wf_TableRow($tablecells, 'row1'); // Перебираємо всіх користувачів foreach ($alllogins as $io=>$eachlogin) { $userlogin=$eachlogin['login']; $userip=$eachlogin['IP']; //Збираючи для кожного рядка таблички $tablecells=wf_TableCell($userlogin); $tablecells.=wf_TableCell($userip); $tablecells.=wf_TableCell(@$allrealnames[$userlogin]); $tablecells.=wf_TableCell(@$alladdress[ $userlogin]); $tablerows.=wf_TableRow($tablecells, 'row3'); } // оголошуємо як результат табличку з попередньо зібраними рядками // а також шириною в 100%, бордюром в 0 і класом sotrable $result=wf_TableBody($tablerows, '100%', '0', 'sortable'); } else { //якщо немає натякаємо що їх немає $result=__('No users found'); } // виводимо наш результат за допомогою функції show_window show_window(__('Sample module'), $result); } else { // якщо ні - вивалюємо на нього помилку про відмову в доступі show_error(__('You cant control this module')); } ?>
Доступ до нашого модуля ми можемо отримати за допомогою посилання ?module=samplemod, в результаті чого ми повинні побачити приблизно таке:
Як бачите, замість рядків Real Name і Address у нас автоматично підставилися їхні мовно-залежні заміни зі словника поточної локалізації. Не перекладеним залишився один рядок Sample module, про який рушій локалізації поки що нічого не знає. Давайте перекладемо його скажімо російською мовою для початку.\
Зробити це досить просто - потрібно створити файл /languages/russian/samplemod.php такого змісту:
<?php $lang['def']['Sample module'] = 'Модуль для прикладу'; $lang['def']['Yet another string'] = 'Ще якийсь рядок'; ?>
Після чого ми побачимо як рядок локалізувався сам по собі в нашому модулі:
З нестандартних речей, чужих чистому PHP, ми використовували тільки функції бібліотеки api.astral для збирання таблиць за допомогою wf_, що не є об'язковою, просто виглядає красивіше та читабельніше, а також висновок крізь show_window($title,$data) замість print(), що вже є об'язковою для роботи шаблонізатора фреймворка.
А що робити, якщо нашому модулю потрібна якась бібліотека/клас потрібна йому одному? Варіантів є кілька. Перший з них менш красивий, але більш портабельний - вставити її прямо всередину нашого модуля в modules/general/smaplemod/index.php. Другий - просто покласти цю бібліотеку в директорію modules/engine/. У цьому разі вона буде довантажена до виконання нашого модуля. Хорошим тоном у цьому випадку буде переконатися, що під час свого завантаження вона не буде виробляти якогось виводу, і друге - постарайтеся уникати створення великих об'єктів у цій бібліотеці, щоб уникнути деградації продуктивності загалом. Що мається на увазі під цим? Наведемо на прикладі бібліотеки, яка описує якийсь клас SampleClass і знаходиться в modules/engine/sampleClass.php
<?php class SampleClass { protected $data=array(); public function __construct() { $this->loadData(); } protected function loadData() { $this->data=...... } } $sampleObject=new SampleClass(); // вот этого тут быть не должно - ему место в modules/general/samplemod/index.php ?>
Також чудовим (і рекомендованим!) способом може бути поміщення вашої бібліотеки в api/libs/, звідки її може підхопити автозавантажувач, якщо ім'я класу створюваного об'єкта відповідає імені бібліотеки з префксом “api.” у лаверкейсі. Для прикладу вище це має бути файл api/libs/api.sampleclass.php. Під час створення об'єкта $sampleObject=new SampleClass(); цю бібліотеку буде автоматично завантажено, і вам взагалі нічого не потрібно для цього робити. Ця механіка з'явилася починаючи з релізу Ubilling 0.8.6 Chainsaw.
А як додаються модулі на панель завдань? Ну там з іконками, правами та опціями? А все так само дуже просто - розкладанням потрібних файликів у потрібні місця. Починаючи з релізу 0.8.0 цими місцями є директорія config/taskbar.d/, а точніше її підкаталоги. Припустимо, наш тестовий модуль є з нашої точки зору звітом. Також ми хочемо, щоб вмикався він за допомогою необов'язкової опції alter.ini на ім'я SAMPLE_ENABLED. Разом кладемо файлик sample.ini в директорію config/taskbar.d/reports/
; Ідентифікатор модуля. Повинен бути як мінімум унікальним. ID="samplemod" ; Підпис іконки модуля - буде автоматично локалізовано поточною локаллю. NAME="Sample module" ; URL нашого модуля. Не повірите - буде клікабельним :) URL=""?module=samplemod" ; Іконка модуля. Спочатку намагається знайтися в директорії taskbar поточного скіна, якщо не існує - у глобальному skins/taskbar. ICON="goat.gif" ; Право, яке вимагає модуль. Ну як мінімум право, яке потрібне для показу іконки. NEED_RIGHT="SAMPLE" ; Опція конфіга alter.ini необхідна для показу іконки таскбара. NEED_OPTION="SAMPLE_ENABLED" ; Цей параметр сигналізує, що опція є необов'язковою. ; Якщо видалити цей параметр - панель завдань буде кричати про відсутню опцію. UNIMPORTANT=1 ; Тип елемента. У нашому випадку це icon - типова іконка з підписом. Є ще widget але про це пізніше. TYPE="icon"
А що ж із віджетами, і як вони взагалі виглядають? А ось якось так так.