Создание приложений на MaxSite CMS. Пример - список TODO

Рубрика: MaxSite CMS -> Основы
Воскресенье, 16 августа 2009 г.
Просмотров: 1947
Подписаться на комментарии по RSS
]]>
]]>

На MaxSite CMS можно создавать самые различные приложения. Я отслеживаю разные публикации, где авторы предлагают какие-то свои наработки на PHP и сопутствующих: HTML, jQuery и т.д. Главная проблема то, что такие демо-примеры нужно еще модернизировать до практического применения.

Данная статья показывает, что MaxSite CMS подходит для решения самых разных задач, а не только тех, которые «идут в коробке». В качеств примера я расскажу как можно сделать свой список дел - TODO.

Для начала у нас должна быть установлена MaxSite CMS. Если мы хотим сделать свое приложение (отдельное), то в принципе нам не особо и нужна админ-панель и все её настройки. MaxSite CMS не выполняет лишнего кода: вначале происходит подключение CodeIgniter, после этого проходит инициализация системы и управление передается в шаблонный index.php. Грубо говоря, если мы хотим получить «чистое» приложение, то мы просто отключим все плагины и в своем шаблоне в файле index.php разместим нужный код.

Такой путь конечно интересен, но мы пойдем чуть-чуть по-другому, чтобы можно было подключить наше приложение к любому шаблону. (Ну хотя бы потому что любое приложение всё равно требует минимального дизайна.)

Тут два варианта - сделать отдельный плагин или отдельный файл в шаблоне. По сути они практически идентичные, за исключением того, что плагин более «вещь в себе». И, наверное, если бы не учебный характер статьи, то я бы делал именно плагином. Но на этот раз мы выберем файл в каталоге шаблона.

Итак определимся с ТЗ.

  • Наше приложение будет вызываться по адресу http://сайт/todo.
  • Показывать список задач будем только юзерам (не комюзерам!).
  • На странице нужно сделать возможность создавать новые задачи, удалять старые, редактировать текст, дату и метки.
  • Обеспечить сортировку таблицы задач.

Дальше я буду генерировать код, обильно сопровождая его комментариями.


Адрес приложения

В MaxSite CMS можно «перехватывать» URL несколькими способами и мы остановимся на самом простом: с помощью mso_segment(). Открываем шаблоный index.php и перед «custom_page_404» добавляем условие:

  1.  ...
  2.  elseif (mso_segment(1)=='todo') require('todo/todo.php');
  3.  ...

То есть по адресу «http://сайт/todo» подключается файл «todo/todo.php». Наше приложение мы разместим в подкаталоге шаблона. Естественно адрес, файл и каталог могут быть произвольными.

Чтобы наш список задач «вписался» в дизайн шаблона, подключим его начальную и конечную часть. Например у меня файл todo.php такой:

  1.  <?php if (!defined('BASEPATH')) exit('No direct script access allowed');
  2.    
  3.  # начальная часть шаблона
  4.  require(getinfo('template_dir') . 'main-start.php');
  5.    
  6.  echo NR . '<div class="type type_todo">' . NR;
  7.    
  8.  echo 'наш todo';
  9.    
  10.  echo NR . '</div><!-- class="type type_todo" -->' . NR;
  11.    
  12.  # конечная часть шаблона
  13.  require(getinfo('template_dir') . 'main-end.php');
  14.  
  15.  ?>

Данный код для вас не вызовет никаких сложностей, просто отмечу, что я обрамил наш будущий вывод в блоки div.type_todo с целью произвольного оформления с помощью CSS.


Показывать список задач будем только юзерам

Задачка решается с помощью is_login():

  1.  if (is_login())
  2.  {
  3.   echo 'наш todo';
  4.  }
  5.  else
  6.  {
  7.   echo NR . '<div class="not_login">У вас нет прав для просмотра списка задач!</div>' . NR;
  8.   echo mso_login_form(); # сразу форму логина выводим
  9.  }

Кстати константа «NR» это перенос строки в HTML-коде. С «NR» генерируемый код получается более читабельным.


Где и как храним данные?

Теперь стоит определиться как и где хранить наши данные. MaxSite CMS предоставляет сразу несколько вариантов. Первый - обычная база данных. Если бы мы выбрали этот вариант, то алгоритм был-бы такой. При «входе» в todo.php нужно проверять существование нашей таблицы. Если её нет, то делаем её (можно вынести в отдельный файл).

Второй вариант - обычные опции. Как известно в MaxSite CMS в опциях можно хранить любые данные, включая и сложные, например массивы. Но нам этот вариант не подойдет потому что мы предполагаем, что данных может оказаться много: нет смысла увеличивать опции за счет нашего приложения.

Третий вариант - использовать float-опции. Это опции, которые хранятся в виде отдельных файлов в каталоге uploads. Эти опции и были придуманы для того, чтобы хранить большие объемы информации. Именно поэтому мы и выберем этот вариант.

Работать с float-опциями очень просто. В функциях указывает ключ и тип опции и, если нужно - новые данные. Например у нас может быть так:

  1.  $todo = mso_get_float_option('todo', 'todo', array());

В данном случае мы получаем опцию с ключом «todo» (произвольно), тип - «todo» (произвольно) и в случае отстуствия возвращается пустой массив.

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

  1.  [id] => array
  2.   [data] => 'дата'
  3.   [text] => 'текст'
  4.   [tag] => 'метка'
  5.   [progress] => 'ход выполнения'

Думаю, что для нас этого вполне будет достаточно, тем более, что добавить другие поля не составит для вас большого труда.


Прием данных

Поскольку у нас будут какие-то действия со страницей (отправка данных), то мы будем использовать классический алгоритм приема данных: вначале смотрим была ли отправка POST; если была, то принимаем данные и обновляем опции; потом выводим форму/данные.

Данный алгоритм используется в MaxSite CMS много раз, поэтому сразу приведу примерный код (он буде немного меняться дальше по тексту).

  1.  if ( $post = mso_check_post(array('f_session_id', 'f_submit', 'f_todo')) )
  2.  {
  3.   mso_checkreferer(); // защита рефера
  4.    
  5.   $todo = $post['f_todo']; // данные формы
  6.    
  7.   mso_add_float_option('todo', $todo, 'todo'); // сохранили опции
  8.    
  9.   echo '<div class="update">Обновлено!</div>'; // вывели сообщение
  10.  }

Грубо говоря, мы сразу в форме определяем поля с именами f_todo[] и тем самым получаем готовый массив POST.


Вывод данных

Вывести данные можно несколькими способами, мы ограничимся обычной таблицей. Для этого воспользуемся библиотекой CodeIgniter «Table». Поскольку мы планируем сортировку по полям/столбцам, то сразу пропишем id «pagetable» и класс «tablesorter», которые используются jQuery-плагином «tablesorter». (В принципе можно и другие именования использовать, тут дело привычки.)

Всю таблицу заключим в одну форму. А строки таблицы сформируем в цикле, обходя наш массив заданий $todo. Вот по такой схеме:

  1.      # подключаем CodeIgniter
  2.   $CI = & get_instance();
  3.     
  4.   # библиотека для таблицы
  5.   $CI->load->library('table');
  6.     
  7.   # конфигурация таблицы
  8.   $CI->table->set_template(array (
  9.   'table_open'   => '<table border="0" width="100%" id="pagetable" class="tablesorter">',
  10.   'row_alt_start'   => '<tr class="alt">',
  11.   'cell_alt_start'   => '<td class="alt">',
  12.   'heading_row_start'    => NR . '<thead><tr>',
  13.   'heading_row_end'       => '</tr></thead>' . NR,
  14.   'heading_cell_start'   => '<th style="cursor: pointer;">',
  15.   'heading_cell_end'      => '</th>',
  16.     ));
  17.     
  18.   # укажем заголовки
  19.   $CI->table->set_heading('№', 'Статус', 'Текст', 'Дата', 'Метка');
  20.  
  21.    
  22.   echo '<h1>Список задач todo</h1>';
  23.    
  24.   # цикл вывода
  25.   foreach ($todo as $id => $t)
  26.   {
  27.   # тут будут наши поля
  28.   $progress = '...';
  29.   $text = '...';
  30.   $data = '...';
  31.   $tag = '...';
  32.     
  33.   $CI->table->add_row($id, $progress, $text , $data, $tag);
  34.   }
  35.     
  36.   echo '<form action="" method="post">' . mso_form_session('f_session_id');
  37.   echo $CI->table->generate(); // вывод подготовленной таблицы
  38.   echo '<input type="submit" name="f_submit" value="Сохранить изменения" />';
  39.   echo '</form>';

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


Добавление нового задания

Сделать это можно с помощью еще одной формы. Разместим нужные поля сразу после таблицы.

  1.  echo '<h2>Добавить новое задание</h2>
  2.  <form action="" method="post">' . mso_form_session('f_session_id_new') . '
  3.  <p><strong>Текст</strong></p><textarea name="f_todo_new[text]"></textarea>
  4.  <p><strong>Метки</strong> <input name="f_todo_new[tag]" type="text" value=""></p>
  5.  <input type="submit" name="f_submit_new" value="Добавить" />
  6.  </form>';

Это еще одна форма, где мы прописываем поля f_todo_new. Мы не ставим дату и прогресс, потому что для нового задания это можно сделать автоматом.

Теперь нам нужно принять отправленные данные. Будем проверять в POST поля нового задания «f_todo_new». Привожу сразу готовый код с комментариями.

  1.  if ( $post = mso_check_post(array('f_session_id_new', 'f_submit_new', 'f_todo_new')) )
  2.  {
  3.   mso_checkreferer();
  4.    
  5.   if ($todo_new = $post['f_todo_new'])
  6.   {
  7.   # текущие опции
  8.   $todo = mso_get_float_option('todo', 'todo', array());
  9.    
  10.   # добавим новую задачу
  11.   $todo[] = array(
  12.   'text' => $todo_new['text'],
  13.   'tag' => $todo_new['tag'],
  14.   'data' => date('Y-m-d H:i:s'),
  15.   'progress' => '0');
  16.    
  17.   # и в опции
  18.   mso_add_float_option('todo', $todo, 'todo');
  19.    
  20.   echo '<div class="update">Задание добавлено</div>';
  21.   }
  22.   else
  23.   echo '<div class="error">Ошибка</div>';
  24.   }

Как видите здесь обработка немного сложнее, потому что вначале нам нужно получить текущие опции и потом добавить к ним еще один элемент массива.


Отображение таблицы

Теперь мы можем вернуться к отображению таблицы. Нам нужно сформировать поля формы в цикле вывода. Кроме этого нам нужно предусмотреть какую-то опцию, отметив которую, задание удаляется. Сделать это можно с помощью обычного checkbox. Добавим его под статус/прогресс.

В итоге получается такой код.

  1.  # цикл вывода
  2.  foreach ($todo as $id => $t)
  3.  {
  4.   # формируем наши поля
  5.   $progress = '<input type="text" name="f_todo[' . $id . '][progress]" value="' . $t['progress'] . '" />';
  6.   $progress .= '<br /><label><input type="checkbox" name="f_todo[' . $id . '][delete]" /> Удалить</label>';
  7.    
  8.   $text = '<textarea name="f_todo[' . $id . '][text]">' . htmlspecialchars($t['text']) . '</textarea>';
  9.   $data = '<input type="text" name="f_todo[' . $id . '][data]" value="' . $t['data'] . '" />';
  10.   $tag = '<input type="text" name="f_todo[' . $id . '][tag]" value="' . $t['tag'] . '" />';
  11.    
  12.   $CI->table->add_row($id + 1, $progress, $text , $data, $tag);
  13.  }

Теперь следует объяснить один момент. В HTML поля типа checkbox передаются только в случаях, если они отмечены/выбраны. Это создает некоторую трудность, но в нашем случае это даже на пользу: мы просто смотрим наличие поля f_todo[ID][delete] и если оно есть, то удаляем задание.

Если вы вернетесь в начало и посмотрите код приема f_todo, то увидите, что мы напрямую добавляли входящий массив в опции. Но из-за «delete» нам придется немного изменить алгоритм: мы делаем новый массив и в него добавляем данные, только если нет f_todo[ID][delete]. Потом этот массив и сохраняем в опции.

  1.  if ( $post = mso_check_post(array('f_session_id', 'f_submit', 'f_todo')) )
  2.  {
  3.   mso_checkreferer();
  4.   $todo = $post['f_todo'];
  5.   $todo_new = array();
  6.    
  7.   foreach ($todo as $t)
  8.   if (!isset($t['delete'])) $todo_new[] = $t;
  9.    
  10.   mso_add_float_option('todo', $todo_new, 'todo');
  11.   echo '<div class="update">Обновлено!</div>';
  12.  }

Данный код последний, который отвечает за функциональность нашего приложения. Остались последние штрихи.


Сортировка таблицы

Для сортировки мы будем использовать jQuery-плагин «tablesorter». Он входит в комплект MaxSite CMS, поэтому всё, что нам нужно - это добавить код вызова и немного js (я добавил немного анимации). Сделаем это перед отображением таблицы.

  1.  echo mso_load_jquery('jquery.tablesorter.js');
  2.  echo '
  3.  <script type="text/javascript">
  4.  $(function() {
  5.    $("table.tablesorter th").animate({opacity: 0.7});
  6.    $("table.tablesorter th").hover(function(){ $(this).animate({opacity: 1}); }, function(){ $(this).animate({opacity: 0.7}); });
  7.    $("#pagetable").tablesorter();
  8.  });  
  9.  </script>
  10.  ';

Так же мы предполагаем, что вы уже подключили в шаблоне саму jQuery. Если нет, то делается это одной строчкой:

  1.  mso_load_jquery();


Подключаем CSS

Здесь нам придется пойти на небольшую хитрость, поскольку подключить css-файл лучше в секции head. Для этого нам нужно «прицепиться» к хуку «head». То есть нам до вызова первой части шаблона нужно написать функцию, которая будет вызываться по хуку.

  1.  mso_hook_add('head', 'todo_head');
  2.  function todo_head($args = array())
  3.  {
  4.   echo '<link type="text/css" rel="stylesheet" href="' . getinfo('stylesheet_url') . 'todo/todo.css" media="screen" />';
  5.   return $args;
  6.  }

Таким образом всё оформление мы переносим в файл todo.css. В принципе можно и не делать хук, а вручную дописать в основном css-файле шаблона нужные стили. Но по мне, так лучше делать это автоматом.


Заключение

Данная статья занимает больше места и времени прочтения, чем результирующий код. Чтобы было легче разобраться, я выкладываю готовый (чуточку измененный вариант) нашего приложения 141. Если бы мы делали «чистое» приложение на MaxSite CMS, то все наши изменения - это отключение проверки is_login() на какой-то свой вариант.

Ну и конечно я не ставил цель поразить вас функционалом и оформлением. Думаю, что те, кого данный пример заинтересовал смогут оформить вывод по своему вкусу. Главное, чтобы вы убедились, что MaxSite CMS подходит для самых разных задач.

]]>twitter.com Google Buzz google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru]]>

Комментариев: 7

Вы можете получать новые комментарии к этой записи по RSS или оформить подписку на все комментарии сайта. Или даже на все новые записи сайта. Не знаете, как это сделать?
  1. 2009-08-17 в 01:21:48 | Wave
    ]]>]]>

    Кстати, сейчас подумал. В отличии от базы данных, данные из флоат-опции можно прочесть и без пароля. Правда, их ещё нужно найти, что практически нереально…

  2. 2009-08-17 в 08:51:13 | MAX
    ]]>]]>

    Да, верно. Впрочем, если нужна повышенная секретность, то можно прописать и шифрование. smile

  3. 2009-09-22 в 16:46:34 | quest

    Все в общем-то понятно Не ясно только одно, почему в названии системы "MaxSite CMS" "засвечено" - CMS smirk, если вместо управления контентом из админки, по определению(Content Manager System), требуется "генерировать код" question

    Есть несколько типовых приложений: "Community", "CK"- Constructor Kit (таблицы, поля пользователя), "eCommerce", "Catalog", ... , которые значительно расширят аудиторию ПОЛЬЗОВАТЕЛЕЙ (не генераторов кода)

    Может разработчикам собраться духом и выложить несколько плагинов - "скелетов" соответствующего функционала question

    Ведь тут прямая зависимость: чем больше пользователей-"не программистов", тем больше профессионалов войдут в проект

  4. 2009-09-22 в 16:58:49 | user

    Как грамотно построить приложение, использующее таблицу пользователя

    Ваша "Model" несколько отлична от "классики жанра"

    Можно изложить отдельным уроком?

    Благодарю

  5. 2009-09-22 в 19:05:40 | user

    "Допишем в ТЗ" - в админке страница с формой ввода данных в таблицу пользователя

    Где-то там, не в шаблоне, страница с формой вывода данных.

    Данные выводим в стандартный шаблон из набора дистрибутива...

    Этот урок будет хорошим дополнением к рассмотренному выше wink, т.к. способ только упоминался в возможном решении, но не рассматривался

  6. 2009-11-09 в 22:49:01 | Dj
    elseif (mso_segment(1)=='todo') require('todo/todo.php');
    

    куда конкретно это надо прописывать? а то куда ни вставлял, везде ошибки вылетают.

  7. 2009-11-10 в 08:41:07 | MAX
    ]]>]]>

    В шаблонный index.php.

Оставьте комментарий!

Не регистрировать/аноним

Используйте нормальные имена. Ваш комментарий будет опубликован после проверки.

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



grin LOL cheese smile wink smirk rolleyes confused surprised big surprise tongue laugh tongue rolleye tongue wink raspberry blank stare long face ohh grrr gulp oh oh downer red face sick shut eye hmmm mad angry zipper kiss shock cool smile cool smirk cool grin cool hmm cool mad cool cheese vampire snake excaim question

(обязательно)