Программирование компонента для InstantCMS

10 апреля 2012 - Dream

 

Файлы и папки

Все компоненты хранятся в папке components
Каждый компонент лежит в собственной папке, название которой совпадает с названием компонента 1).

Компоненты обычно состоят из двух частей - лицевой (frontend) и служебной (backend). 
Лицевая часть доступна при просмотре сайта, служебная - для настройки компонента в панели управления. 
Если компонент не имеет настроек, то служебная часть может отсутствовать.

www.instantcms.ru_images_docs_com-tree.jpg

На рисунке показан типичный состав папки, на примере компонента content.
В папке компонента могут быть следующие составляющие:

  • Любые папки с файлами, необходимые для работы компонента (например jsimages и т.п.) - не обязательно
  • index.html - пустой файл, нужен для предотвращения прямого доступа к папке через адрес
  • frontend.php - файл контроллера компонента, в нем реализуется основная логика - обязателен
  • model.php - файл модели компонента - обязателен, если компонент обращается к БД
  • psearch.php - файл для интеграции с поиском по сайту - не обязателен
  • prss.php - файл для интеграции с RSS - не обязателен
  • router.php - файл содержащий правила роутинга - обязателен, если вывод компонента состоит более чем из одной страницы
  • install.php - файл установщика компонента - обязателен, если компонент распространяется отдельно от системы

Приведенный список показывает файлы, необходимые для работы лицевой части компонента.

Если компоненту требуется интерфейс для настройки через панель управления, то дополнительно создается папка с именем компонента внутри папки /admin/components
и в ней - файл backend.php:

www.instantcms.ru_images_docs_com-tree-adm.jpg

Если компонент имеет страницы вывода на сайте, то для каждой из них должен быть создан tpl-шаблон внутри папки /templates/_default_/components
Название каждого tpl-шаблона формируется по принципу:

com_<название компонента>_<название страницы>.tpl

Например для страницы «Просмотр статьи» компонента «content» шаблон будет называться com_content_read.tpl:

www.instantcms.ru_images_docs_com-tree-tpl.jpg

 

Создание компонента на примере

Давайте рассмотрим устройство компонентов на примере простого компонента «Гостевая книга». 
Компонент должен будет уметь:

  • Показывать список всех добавленных в гостевую книгу сообщений, по адресу: site.ru/guestbook
  • Показывать одно конкретное сообщение отдельно, по адресу: site.ru/guestbook/messageXX.html (где XX - id сообщения)
  • Принимать новые сообщения от зарегистрированных пользователей, по адресу: site.ru/guestbook/add.html
  • Администратор сайта сможет удалять сообщения, по адресу site.ru/guestbook/deleteXX.html

Каждое сообщение в нашей гостевой книге будет содержать следующую информацию:

  • Заголовок (title)
  • Текст сообщения (message)
  • Автор (user_id)
  • Дата сообщения (pubdate)

Первый шаг который вам необходимо сделать это создать папку /components/guestbook в папке вашего сайта.

Подготовка таблиц в базе данных

Все сообщения нашей гостевой книги будут храниться в таблице cms_guestbook
При установке системы пользователи могут выбирать любые префиксы таблиц, отличные от «cms_», но внутри кода системы всегда используется только этот префикс. Замена префикса «cms_» на настоящий происходит внутри ядра системы при каждом запросе в БД.

Создадим в базе данных таблицу cms_guestbook:

CREATE TABLE `cms_guestbook` (
 `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
 `title` VARCHAR( 200 ) NOT NULL ,
 `message` TEXT NOT NULL ,
 `user_id` INT NOT NULL ,
 `pubdate` DATETIME NOT NULL ,
INDEX ( `user_id` )
) ENGINE = MYISAM ;

Поле user_id сделаем индексом, чтобы в дальнейшем иметь возможность получать быструю выборку записей принадлежащих одному конкретному пользователю.

При добавлении таблиц через phpMyAdmin или любую другую программу обязательно сохраняйте тексты создающих их запросов. Они пригодятся позже, при подготовке инсталлятора компонента.

 

Модель компонента

Модель представляет из себя PHP-класс, внутри которого реализуются методы для извлечения (get), создания (add), изменения (update) и удаления (delete) записей из базы данных.

Создайте файл model.php в папке компонента и поместите в него каркас модели:

<?php
if(!defined('VALID_CMS')) { die('ACCESS DENIED'); }
 
class cms_model_guestbook{
 
    function __construct(){
        $this->inDB = cmsDatabase::getInstance();
    }
 
    // ... здесь будут методы для работы с данными ...
}

Название класса модели формируется из двух частей: cms_model_ + <название_компонента>

Теперь реализуем метод для добавления сообщений нашей гостевой:

    // ...
 
    public function addMessage($title, $message, $user_id) {
 
        //готовим запрос для добавления записи
        $sql = "INSERT INTO cms_guestbook (title, message, user_id, pubdate)                 VALUES ('{$title}', '{$message}', '{$user_id}', NOW())";
 
        //выполняем запрос
        $this->inDB->query($sql);
 
        //если возникла ошибка, вернем false
        if ($this->inDB->error()) { return false; }
 
        //если ошибок не было, вернем ID новой записи
        return $this->inDB->get_last_id('cms_guestbook');
 
    }
 
    // ...

Примечание: Обратите внимание что в этой функции мы не реализуем никакой логики, кроме добавления записи в базу данных. Функция принимает все необходимые данные (заголовок, текст и автора сообщения) в качестве аргументов, формирует запрос и выполняет его.

Для работы с базой данных используется объект $this→inDB, который мы получили ранее, в конструкторе модели:

    // ...
 
    function __construct(){
        $this->inDB = cmsDatabase::getInstance();
    }
 
    // ...

Полный список методов этого объекта вы можете посмотреть в файле /core/classes/database.class.php

Примечание: Обычно функции модели возращают true или false, чтобы контроллер компонента мог судить об удачности выполнения операции. Однако в случае с добавлением записей считается за правило возращать ID вставленной записи в случае удачи и false в случае ошибки.

Следующим шагом создадим метод для удаления сообщения:

    // ...
 
    public function deleteMessage($message_id) {
 
        $sql = "DELETE FROM cms_guestbook WHERE id = '{$message_id}'";
 
        //выполняем запрос
        $this->inDB->query($sql);
 
        //если возникла ошибка, вернем false
        if ($this->inDB->error()) { return false; }
 
        //если ошибок не было, вернем true
        return true;
 
    }
 
    // ...

Он имеет такую же структуру, меняется лишь запрос и входящие параметры (для удаления достаточно знать только ID сообщения).

Остался последний нереализованный метод - для извлечения сообщений из базы. Давайте напишем его:

    // ...
 
    public function getMessages() {
 
        //Подключим ядро движка, оно потребуется ниже
        $inCore = cmsCore::getInstance();
 
        $sql = "SELECT id,                        title,                        message,                        user_id,                        pubdate                 FROM cms_guestbook";
 
        //выполняем запрос
        $result = $this->inDB->query($sql);
 
        //если возникла ошибка, вернем false
        if ($this->inDB->error()) { return false; }
 
        //если не было получено ни одного сообщения - вернем false
        if (!$this->inDB->num_rows($result)) { return false; }
 
        //массив в который мы будем складывать сообщения
        //он необходим для того, чтобы мы могли вернуть все сообщения
        //за один вызов функции
        $messages = array();
 
        //получаем все сообщения по-очереди и складываем в массив
        while ($message = $this->inDB->fetch_assoc($result)){
 
            //c помощью метода ядра форматируем дату сообщения
            //(приводим ее в русский вид)
            $message['pubdate'] = $inCore->dateFormat($message['pubdate']);
 
            //и добавляем сообщение в массив
            $messages[] = $message;
 
        }
 
        //возращаем массив сообщений
        //название каждого элемента в нем совпадает с названием полей
        //в таблице cms_guestbook
        return $messages;
 
    }
 
    // ...

Примечание: В данный момент функция getMessages() имеет простейший вид - в ней не предусмотрено разбиение на страницы, выборки сообщений от конкретной даты и конкретного автора. Эти возможности мы добавим в следующей части данного руководства. Сейчас наша задача изучить общие принципы.

Теперь наша модель имеет 3 метода - для создания, удаления и извлечения сообщений. На первое время этого нам достаточно и можно перейти к созданию контроллера компонента.

 

Контроллер компонента

Основная логика работы компонента реализуется в файле frontend.php.

Обзор контроллера

В кратце, работа контроллера сводится к следующим этапам:

  • Инициализация: Подключение всех необходимые классов (ядро, пользователи, …) и библиотек (теги, карма, …), загрузка модели
  • Постановка задачи: Получение параметров из URL страницы и определение действия, которое нужно совершить
  • Загрузка данных: Получение нужных записей из базы данных (или сохранение/удаление записей) с помощью модели
  • Решение задачи: Совершение необходимых операций над данными
  • Вывод: Передача обработанных данных в шаблон

:!: Важно: Контроллер должен заниматься только обработкой данных. В нем не должно быть работы с базой (функций *query()) и любого вывода (операторов echo). Взаимодействие с базой должно происходить только через модель, вывод данных - только через шаблоны.

Теперь создайте файл frontend.php в папке компонента и поместите в него каркас контроллера:

<?php
function guestbook(){
 
    //Инициализируем объекты, которые нам понадобятся
    //для работы: ядро, страница(шаблонизатор) и пользователь
    $inCore = cmsCore::getInstance();
    $inPage = cmsPage::getInstance();
    $inUser = cmsUser::getInstance();
 
    //загрузим модель
    $inCore->loadModel('guestbook');
 
    //создадим объект модели
    $model = new cms_model_guestbook();
 
    //Получаем текущее действие из URL страницы
    $do = $inCore->request('do', 'str', 'view_all');
 
 
    if ($do == 'view_all'){
 
        // ... здесь будет код для вывода всех сообщений ...
 
    }
 
 
    if ($do == 'add'){
 
        // ... здесь будет код для добавления сообщений ...
 
    }
 
    if ($do == 'delete'){
 
        // ... здесь будет код для удаления сообщений ...
 
    }
 
}

Как вы уже заметили, код контроллера состоит из одной большой функции, название которой совпадает с идентификатором компонента. В нашем случае это guestbook.

Внутри функции инициализируются нужные объекты и загружается модель, написанная нами в предыдущей части. Затем заполняется переменная $do, которая будет хранить в себе название текущей задачи. Пока наш компонент будет уметь решать три вида задач:

  • view_all - показ списка всех сообщений гостевой книги
  • add - добавление сообщений
  • delete - удаление сообщений

Давайте реализуем логику для каждой из этих задач.

Вывод всех сообщений

Для получения сообщений из базы данных мы будем использовать метод getMessages() нашей модели. Как вы помните, этот метод возвращает массив. Нам нужно получить массив и передать его в шаблон где сообщения будут оформлены и выведены на страницу.

Пишем код:

    // ...
 
    if ($do == 'view_all'){
 
        //1. получаем сообщения из базы
        $messages = $model->getMessages();
 
        //2. узнаем, является ли текущий пользователь администратором
        $is_admin = $inUser->is_admin;
 
        //3. Устанавливаем заголовок страницы
        $inPage->setTitle("Гостевая книга");
 
        //4. подключаем шаблонизатор Smarty и сообщаем ему имя шаблона
        //   который нужно будет использовать для вывода списка сообщений
        $smarty = $inCore->initSmarty('components', 'com_guestbook_view_all.tpl');
 
        //5. передаем в шаблон список сообщений и флаг администратора
        $smarty->assign('messages', $messages);
        $smarty->assign('is_admin', $is_admin);
 
        //6. выводим шаблон на экран
        $smarty->display('com_guestbook_view_all.tpl');
 
        //7. завершаем работу компонента
        return;
 
    }
 
    // ...

Разберем подробнее что происходит:

1. Сначала мы вызываем метод getMessages() модели и результат (список сообщений) сохраняем в переменную $messages. Помните, что если в базе не окажется сообщений, то в этой переменной будет не массив, а логическое значение false. Этот момент мы рассмотрим позже, при создании шаблона.

2. В начале компонента мы инициализировали объект $inUser, который хранит в себе информацию о текущем пользователе (который запрашивает страницу). Объект имеет несколько свойств, описывающих пользователя. Их названия и содержание совпадают с полями в таблице cms_users. Например:

  • $inUser→id : идентификатор пользователя (равен нулю если пользователь не авторизован)
  • $inUser→login : логин
  • $inUser→nickname : никнейм
  • $inUser→email : почтовый адрес
  • $inUser→is_admin : логическое свойство (true/false), показывающее входит ли пользователь в группу администраторов

3. Передаём объекту inPage созданному в самом начале заголовок страницы.

4. Подключаем шаблонизатор. Обратите внимание на два входящих параметра функции initSmarty(). Первый из них указывает название папки внутри папки шаблона сайта, второй - название файла шаблона компонента. Как вы помните, это название формируется по схеме com_<компонент>_<действие>.tpl. Соблюдение этого принципа позволит вам быстро находить нужный файл в дальнейшем.

5. Передаем переменные в шаблон. Для каждой переменной вызывается метод assign() шаблонизатора Smarty. Первый аргумент указывает как переменная будет называться в шаблоне (грубо говоря, название тега), второй - откуда брать ее значение. Лучше всего использовать одинаковые названия везде где это возможно, чтобы избегать путаницы.

6. Выводим шаблон. На самом деле вывод на экран будет происходить не здесь, а позже, после подготовки основного шаблона сайта. Однако в контексте контроллера можно считать что метод display() отправляет страницу в браузер.

7. Завершаем работу компонента оператором return. Это даст нам гарантию что никакой код расположенный ниже не выполнится даже случайно.

На примере простого действия по выводу списка сообщений хорошо видно преимущество модели MVC. Для получения сообщений из базы используется метод модели, это значит что при необходимости получить сообщения где-то еще не придется дублировать код. Мы можем добавить любую предварительную обработку данных получаемых из базы не трогая код контроллера. Вывод на экран тоже никак не привязан к коду контроллера и может быть легко заменен.

Следующим шагом создадим интерфейс для добавления сообщений.

Добавление сообщений

Добавление состоит из двух частей: вывода формы для заполнения и ее обработка (сохранение). Определять что нужно сделать - показать форму или сохранить данные - мы будем анализируя входящие данные, переданные скрипту. То есть наша форма будет содержать кнопку отправки:

<input type="submit" name="send" value="Отправить сообщение">

При нажатии на кнопку форма будет отправляться обратно контроллеру и мы сможем проверить существование переменной $_POST['send']. Если она существует, значит нужно принять сообщение и сохранить его. Если нет - значит нужно показать форму:

    // ...    
 
    if ($do == 'add'){
 
        $is_send = $inCore->inRequest('send');
 
        if (!$is_send){            
            //... показываем форму ...            
        }
 
        if ($is_send){
            //... сохраняем сообщение ...
        }
 
    }
 
    // ...

Мы определяем наличие переменной $_POST['send'] при помощи метода inRequest() объекта ядра. Этот метод возращает true/false, в зависимости от наличия переменной.

Далее используем два условных оператора чтобы разделить логику на две части. Мы осознанно используем два if вместо одного if..else, т.к. это повышает читаемость кода (в случае с else нужно скроллить код вверх, чтобы увидеть определение условия для второго блока).

Вывод формы идентичен выводу списка сообщений. Разница лишь в том, что теперь нам не нужно передавать в шаблон никаких параметров:

    // ...    
 
        if (!$is_send){            
 
            //подключаем шаблон и выводим на экран
            $smarty = $inCore->initSmarty('components', 'com_guestbook_add.tpl');
            $smarty->display('com_guestbook_add.tpl');
 
        }
 
    // ...

Мы заранее определились, что каждое сообщение в нашей гостевой книге будет иметь тему (title) и текст (message). В форме будут два поля, значения которых нам нужно получить для сохранения в базу. Чтобы узнать ID автора воспользуемся объектом $inUser.

//...
 
        if ($is_send){
 
            //1. получаем все параметры сообщения
            $title      = $inCore->request('title', 'str');
            $message    = $inCore->request('message', 'str');
            $user_id    = $inUser->id;
 
            //2. если не указана тема или сообщение
            if (!$title || !$message){
 
                //сохраняем текст ошибки в сессию
                cmsCore::addSessionMessage('Укажите тему и сообщение!', 'error');
 
                //и делаем редирект обратно на форму, завершая выполнение скрипта
                $inCore->redirectBack(); exit;
 
            }
 
            //3. добавляем сообщение и получаем его номер
            $message_id = $model->addMessage($title, $message, $user_id);
 
            //4. если номер сообщения получен
            if ($message_id){
                //сохраняем текст успеха в сессию
                cmsCore::addSessionMessage('Сообщение успешно добавлено!', 'success');
            }
 
            //5. если по каким-то причинам сообщение не добавилось
            if (!$message_id){
                //сохраняем текст неудачи
                cmsCore::addSessionMessage('Ошибка добавления сообщения!', 'error');
            }
 
            //6. делаем редирект на список сообщений и завершаем скрипт
            $inCore->redirect('/guestbook'); exit;
 
        }
 
//...

Разберем подробнее:

1. Сначала мы получаем входящие переменные при помощи метода request(). Этот метод может возвращать значения переданные как GET так и POST-запросом и имеет три параметра:

   $inCore->request('название_переменной', 'тип_переменной', 'значение_по_умолчанию');

Название переменной совпадает с названием поля в форме. Тип переменной задается одним из четырех значений:

  • int - число
  • str - строка (html-теги вырезаются)
  • html - html-код (теги не вырезаются)
  • array - массив

Третий параметр задает значение по-умолчанию, которое будет присвоено переменной если она не была передана из формы. Если значение по-умолчанию не задано, используется пустая строка.

2. Далее мы смотрим указаны ли тема и текст сообщения. Если не указаны, помещаем в сессию пользователя уведомление об ошибке с помощью статического метода cmsCore::addSessionMessage(). Первый параметр этого метода - это текст который нужно будет показать пользователю, второй - тип сообщения:

  • error - ошибка (красный текст)
  • success - успех (зеленый текст)
  • info - информация (нейтральный текст)

Непосредственный показ передаваемого уведомления мы должны будем позже реализовать в шаблоне.

Если произошла ошибка (тема или текст не были указаны), после сохранения уведомления в сессию мы делаем редирект на предыдущую страницу и завершаем скрипт.

3. Если ошибок не было, С помощью метода addMessage() нашей модели сохраняем текст сообщения гостевой книги. В ответ получаем id созданного сообщения.

4, 5. Проверяем полученный id, если вместо числа (вдруг) вернется false то мы передадим пользователю сообщение об ошибке, иначе - об успехе.

6. Делаем редирект на список сообщений. Любая обработка форм должна завершаться редиректом, во избежание появления вопроса «Вы хотите отправить данные заново?» со стороны браузера после обновления страницы. Еще один важный момент - любой редирект должен завершаться выходом из скрипта.

Удаление сообщений

Наш компонент должен уметь удалять сообщения из гостевой книги, при условии что пользователь запрашивающий удаление является администратором.

Логика простая:

  1. получаем ID сообщения (будет передаваться методом GET как часть адреса страницы /guestbook/deleteXX.html);
  2. проверяем, является ли текущий пользователь администратором (свойство $inUser→is_admin установлено в true);
  3. если все правильно, удаляем сообщение с помощью метода deleteMessage() определенного нами ранее в модели;
  4. делаем редирект обратно к списку сообщений.

Реализация:

    // ...    
 
    if ($do == 'delete'){
 
        //получаем ID сообщения
        $message_id = $inCore->request('message_id', 'int', 0);
 
        //если ID не получен или пользователь не администратор, делаем редирект обратно
        if (!$message_id || !$inUser->is_admin) {
            $inCore->redirectBack(); exit;
        }    
 
        //удаляем сообщение
        $model->deleteMessage($message_id);
 
        //делаем редирект обратно к списку сообщений
        $inCore->redirectBack(); exit;
 
    }
 
    // ...

Теперь наш контроллер готов, он умеет показывать список сообщений, добавлять новые и удалять имеющиеся. Следующим шагом нам нужно связать действия контроллера с URL-адресами страниц.

 

Роутер компонента

В предыдущей части мы написали контроллер компонента, умеющий выполнять три типа действий: view_all (показ списка сообщений), add (добавление сообщения), delete (удаление сообщений).

Как контроллер узнает какое из этих действий нужно выполнить в конкретный момент? Он смотрит в переменную $do, которую мы определили так:

    //...
 
    //Получаем текущее действие из URL страницы
    $do = $inCore->request('do', 'str', 'view_all');
 
    //...

Переменная $do берет свое значение из адреса страницы (т.е. передается контроллеру методом GET). Если в адресе ее значение не было указано, она принимает значение 'view_all'. То есть, если кто-то наберет в браузере адрес http://site/guestbook, он запустит наш компонент guestbook без каких-либо параметров. Соответственно переменная $do примет значение по-умолчанию – view_all – и мы увидим список всех сообщений гостевой книги.

Теперь разберемся с остальными адресами. Ранее мы договорились что у нас будет два адреса:

  • http://site/guestbook/add.html – для добавления сообщений (действие add контроллера)
  • http://site/guestbook/deleteXX.html – для удаления сообщений (действие delete контроллера), где XX должно будет преобразоваться в переменную $message_id

Нам нужно связать эти адреса страниц с действиями контроллера. Для этого используется роутер компонента.

Роутер представляет из себя файл router.php находящийся в папке компонента:

<?php
    function routes_guestbook(){
 
        $routes[] = array( /* маршрут 1 */ );
 
        $routes[] = array( /* маршрут 2 */ );
 
        return $routes;
 
    }

Внутри файла определяется функция routes_XXX(), где XXX - название компонента (в нашем случае это «guestbook»). Внутри функции заполняется массив $routes, содержащий маршруты. Каждый маршрут связывает URL страницы с действием контроллера. Для нашего контроллера потребуется 2 маршрута:

<?php
    function routes_guestbook(){
 
        //добавление сообщения
        $routes[] = array(
                            '_uri'  => '/^guestbook\/add.html$/i',
                            'do'    => 'add'
                         );
 
        //удаление сообщения
        $routes[] = array(
                            '_uri'  => '/^guestbook\/delete([0-9]+).html$/i',
                            'do'    => 'delete',
                            1       => 'message_id'
                         );
 
    }

Каждый элемент массива $routes тоже является массивом и может содержать следующие записи:

  1. _uri ⇒ регулярное выражение, с которым сравнивается адрес страницы (аналог первой части RewriteRule из .htaccess) - обязательный элемент
  2. параметр ⇒ значение (сколько угодно пар) - опционально
  3. номер сегмента ⇒ параметр (столько же пар, сколько пар круглых скобок в рег.выражении, аналог $1, $2 из .htaccess ) - опционально

Как мы видим, каждый маршрут содержит регулярное выражение с которым будет сравниваться адрес страницы.

После регулярного выражения идут указания – какие параметры передать контроллеру компонента если адрес совпадет с выражением. Например запись:

  'do'    => 'add'

означает что будет создана переменная do со значением 'add'. В коде контроллера мы получим это значение с помощью метода request('do') и узнаем, что требуется показать страницу добавления сообщения.

Второй маршрут (для удаления) подразумевает передачу в компонент еще и части адреса в виде переменной message_id. Взглянем еще раз на шаблон адреса для удаления сообщения:

  '_uri'  => '/^guestbook\/delete([0-9]+).html$/i'

обратите внимание на выражение в круглых скобках: ([0-9]+) и на строчку:

  1       => 'message_id'

буквально эту строку можно трактовать как «совпадение из первых круглых скобок нужно передать под именем message_id». Соответственно, если добавить еще одно выражение в круглых скобках в шаблон адреса, то его значение можно будет передать как:

  2       => 'second_var'

Больше примеров маршрутов вы можете посмотреть в файлах router.php стандартных компонентов InstantCMS.

Любые вопросы связанные с роутингом можно не стесняясь задавать на форуме.

Шаблоны компонента

На данный момент наш компонент практически готов, осталось создать шаблоны.

Шаблона требуется два – один для вывода всех сообщений гостевой книги (com_guestbook_view_all.tpl), другой с формой добавления сообщения (com_guestbook_add.tpl).

Список сообщений

Давайте вспомним участок кода контроллера который отправляет массив сообщений в шаблон:

    // ...
    // получаем шаблонизатор
    $smarty = $inCore->initSmarty('components', 'com_guestbook_view_all.tpl');
 
    // передаем в шаблон список сообщений и флаг администратора
    $smarty->assign('messages', $messages);
    $smarty->assign('is_admin', $is_admin);
 
    // выводим шаблон на экран
    $smarty->display('com_guestbook_view_all.tpl');
    // ...

Мы передаем шаблону две переменных – $messages (массив сообщений) и $is_admin (является ли пользователь администратором).

Теперь создайте файл /templates/_default_/components/com_guestbook_view_all.tpl и поместите в него следующий код:

<h1 class="con_heading">Гостевая книга</h1>
 
<div class="messages">
 
    {foreach key=id item=message from=$messages}
        <div class="message">
            <p><strong>{$message.title}</strong></p>
            <p>{$message.message}</p>
            <p><small>Автор: {$message.author} | Дата: {$message.pubdate}</small></p>
 
            {if $is_admin}
                <p><a href="/guestbook/delete{$message.id}.html">Удалить сообщение</a></p>
            {/if}
        </div>
    {/foreach}
 
</div>
<p><a href="/guestbook/add.html">Добавить сообщение</a></p>

Здесь мы с помощью цикла foreach перебираем массив $messages, рассматривая каждый его элемент как $message. Внутри цикла для каждого сообщения строим <div> и заполняем данными – тема, сообщение, автор, дата. Также при выводе каждого сообщения мы проверяем переменную $is_admin чтобы узнать, является ли пользователь администратором и можно ли ему показывать ссылку на удаление сообщения. В конце списка сообщений мы выводим ссылку на форму добавления нового.

Добавление сообщений

Создайте файл /templates/_default_/components/com_guestbook_add.tpl и поместите в него следующий код:

<h1 class="con_heading">Добавить сообщение</h1>
 
<form action="" method="post">
 
    <div>Тема сообщения:</div>
    <div>
        <input type="text" name="title" />
    </div>
 
    <div>Текст сообщения:</div>
    <div>
        <textarea name="message"></textarea>
    </div>
 
    <p>
        <input type="submit" name="send" value="Отправить" />
    </p>
 
</form>

Мы не заполняем аттрибут action формы, т.к. показ формы и обработка данных из нее происходит в одном и том же действии контроллера (т.е. по одному адресу страницы). Все остальное вполне стандартно.

Теперь перейдите по адресу site.ru/guestbook. Если все было сделано правильно, вы увидите пустой список сообщений. Попробуйте добавить несколько сообщений и посмотреть как они выводятся в списке.

Использование собственных *.css и *.js файлов в шаблоне

Внутри tpl-шаблонов компонента вы можете подключать к странице произвольные CSS и JavaScript-файлы.

Подключение CSS:

{add_css file="templates/my-template/css/style.css"}

Подключение JS:

{add_js file="templates/my-template/js/script.js"}

Пути к файлам лучше не прописывать жестко, как в двух примерах выше, т.к. это привяжет файлы к определенному шаблону. Рекомендуется определять путь к текущему шаблону и нужному файлу внутри контроллера с помощью такого кода:

$inConf = cmsConfig::getInstance();
$template_dir = 'templates/' . $inConf->template . '/';
$my_css = $template_dir . 'styles.css';

Затем передавать переменную $my_css в шаблон и подключать файл таким образом:

{add_css file=$my_css}

Тогда CSS-файл всегда будет браться из текущего шаблона, установленного пользователем.

 

Установка компонента

 

Введение

Если вы планируете распространять свой компонент, то хорошей идеей будет написать для него инсталлятор. При наличии инсталлятора установка компонента для пользователя движка сводится к следующим шагам:

  1. распаковать архив с компонентом на сайте
  2. в админке перейти в раздел «Компоненты» и нажать кнопку «Установка»
  3. щелкнуть по названию компонента и установить его

После этого компонент будет готов к работе.

С точки зрения разработчика установка компонентов состоит из следующих этапов:

  1. регистрация компонента в таблице cms_components
  2. создание и заполнение всех таблиц, необходимых для работы компонента
  3. установка модулей и плагинов поставляемых вместе с компонентом (при наличии таковых)

Подготовка

Прежде чем перейти к написанию инсталлятора нужно подготовить файл с SQL-запросами, создающими и заполняющими таблицу нашего компонента.

1. Через phpMyAdmin или любую другую программу для работы с БД сделайте экспорт структуры таблицы cms_guestbook. Экспортировать данные при этом не нужно, т.к. мы хотим чтобы сразу после установки гостевой книги в ней не было сообщений. После экспорта вы получите такой SQL:

CREATE TABLE `cms_guestbook` (
 `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
 `title` VARCHAR( 200 ) NOT NULL ,
 `message` TEXT NOT NULL ,
 `user_id` INT NOT NULL ,
 `pubdate` DATETIME NOT NULL ,
INDEX ( `user_id` )
) ENGINE = MYISAM ;

Создайте файл install.sql в папке /components/guestbook

В эту же папку поместите файл install.php со следующим содержимым:

<?php
    function info_component_guestbook(){
        $_component['title']        = 'Гостевая кинга'; //Заголовок компонента
        $_component['description']  = 'Гостевая книга позволяет добовлять короткие записи гостям сайта'; //описание компонента
        $_component['link']         = 'guestbook'; //ссылка на компонент
        $_component['author']       = 'Al Gor'; //Автор компонента
        $_component['internal']     = '0';
        $_component['version']      = '0.1'; //версия 
        $inCore = cmsCore::getInstance();
        $inCore->loadModel('guestbook');
        return $_component;
    }
 
    function install_component_guestbook(){
 
        $inCore = cmsCore::getInstance();
        $inDB   = cmsDatabase::getInstance();
        $inConf = cmsConfig::getInstance();
        include(PATH.'/includes/dbimport.inc.php');
        dbRunSQL(PATH.'/components/guestbook/install.sql', $inConf->db_prefix);
 
        if(!cmsActions::getAction('add_message')){
            cmsActions::registerAction('guestbook',
                                        array(
                                                'name'=>'add_message',
                                                'title'=>'Добавление записи в гостевую книгу',
                                                'message'=>'добавляет запись в гостевую книгу %s'
                                             )
                                      );
        }
        return;
    }
}
?>

Для интеграции с полнотекстовым поиском по сайту необходимо:

  1. В базе данных на нужных полях таблицы компонента создать FULLTEXT индекс
  2. В директории /components/линк_компонента/ создать php файл, назвав его psearch.php.
  3. В файле psearch.php объявить функцию search_линк_компонента, т.е. функция должна иметь название: префикс search_ + линк компонента, например search_photos - неизменяемый префиксsearch_ + линк компонента - photos.
  4. В функции search_линк_компонента должны быть два аргумента $query, $look - подготовленный запрос для поиска и тип поиска соответственно.
  5. После отработки функции, результаты должны быть в таблице cms_search.

Разберем пример:

function search_photos($query, $look){
 
        $inDB   = cmsDatabase::getInstance();         // Определяем объект класса БД
	$searchModel = cms_model_search::initModel(); // Определяем объект класса модели компонента "Поиск"
 
        // Сам поисковый запрос
	$sql = "SELECT f.*, a.title as cat, a.id as cat_id FROM cms_photo_files f 			 INNER JOIN cms_photo_albums a ON a.id = f.album_id 			 WHERE MATCH(f.title, f.description) AGAINST ('$query' IN BOOLEAN MODE) AND f.published = 1";
 
	$result = $inDB->query($sql);
	// При наличии результата запроса, обрабатываем его, добавляя результаты в таблицу cms_search
	if ($inDB->num_rows($result)){
 
		while($item = $inDB->fetch_assoc($result)){
 
			$result_array = array();
 
			$result_array['link']        = "/photos/photo".$item['id'].".html"; // основная ссылка на результат
			$result_array['place']       = $item['cat'];                        // заголовок места назначения
			$result_array['placelink']   = '/photos/'.$item['cat_id'];          // ссылка на место назначения
			$result_array['description'] = $searchModel->getProposalWithSearchWord($item['description']); // описание  //результата, прошедшее через метод, который ищет искомые слова в описании
			$result_array['title']       = $item['title'];                      // заголовок результата
			$result_array['pubdate']     = $item['pubdate'];                    // дата публикации найденного материала
			$result_array['session_id']  = session_id();                        // id текущей сессии пользователя
 
			$searchModel->addResult($result_array);                             // Заносим результат в  //таблицу cms_search (если такой результат уже есть, добавлен не будет)
		}
	}
 
	return;
}

Таким образом, задача данной функции непосредственно найти искомый результат и занести его в таблицу cms_search.

 

 

 

 

 

Похожие статьи:

Новости разработчиковкомпонент: Реестр резюме.

Новости разработчиковВакансии v1.9

Рейтинг: +1 Голосов: 1 17646 просмотров
Комментарии (0)

Нет комментариев. Ваш будет первым!