Текст книги "Разрботка расширений для CMS Joomla"
Автор книги: Яна Седова
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 3 (всего у книги 10 страниц)
Проверив, что код вызван из Joomla, мы используем выражение require_once(JApplicationHelper::getPath('admin_html')) для подключения файла admin.myquestions.html.php.
Затем с помощью JTable::addIncludePath() папка tables добавляется к списку директорий, в которых следует искать классы таблиц.
Переключатель switch() вызывает функцию, соответствующую значению переменной $task.
В функции replyToQuestion() создается экземпляр класса TableQuestion для управления записью таблицы. С помощью JRequest::getVar() из переменных запроса извлекается массив cid, хранящий идентификаторы записей. Так как эксперт будет отвечать только на один вопрос за раз, то мы выбираем первый идентификатор и загружаем соответствующую запись. Затем она передается в функцию вывода HTML_questions::replyToQuestion().
Теперь создайте файл /administrator/components/com_myquestions/admin.myquestions.html.php:
Листинг .
Функция HTML_questions::replyToQuestion() выводит на экран уже заполненную форму, значения элементов которой берутся из объекта $row. Форме присвоено название adminForm, чтобы к ней можно было обращаться из JavaScript.
Классы JHTML и JEditor будут рассмотрены позже. Сейчас поясним только те выражения, в которых используются методы этих классов:
echo JHTML::_('date', $row->date,JText::_('DATE_FORMAT_LC3')); выводит дату $row->date в формате DATE_FORMAT_LC3 (один из стандартных форматов, заданных в Joomla).
$editor =& JFactory::getEditor(); echo $editor->display('question', $row->question, '100%', '250', '40', '10'); отображает выбранный администратором HTML-редактор. Если не выбран ни один редактор, то будет отображено поле
echo JHTML::_('calendar', $row->expiration_date, 'expiration_date', 'expiration_date', '%Y-%m-%d'); выводит текстовое поле со значением $row->expiration_date и пиктограмму календаря, при нажатии на которую появляется календарь для выбора даты.
Перед закрывающим тегом выводятся три скрытые элемента. Первый из них хранит значение id записи, т.к. оно необходимо для дальнейшего сохранения отредактированного вопроса. Элемент option хранит название текущего компонента для правильного редиректа в дальнейшем. Третьему скрытому элементу, task, не присвоено значения, чтобы JavaScript-код панели инструментов мог изменять его до отправки формы.
Осталось добавить перевод ключей COM_MYQUESTIONS_AUTHOR, COM_MYQUESTIONS_DATE и др. Откройте файл /administrator/language/ru-RU/ru-RU.com_myquestions.iniи добавьте к его содержимому следующий код:
COM_MYQUESTIONS_AUTHOR="Автор" COM_MYQUESTIONS_DATE="Дата вопроса" COM_MYQUESTIONS_QUESTION="Текст вопроса" COM_MYQUESTIONS_CITY="Город" COM_MYQUESTIONS_EMAIL="e-mail" COM_MYQUESTIONS_IP="IP-адрес" COM_MYQUESTIONS_CATEGORY="Категория" COM_MYQUESTIONS_PUBLISHED="Отображать ли вопрос на сайте" COM_MYQUESTIONS_EXPIRATION_DATE="Дата снятия вопроса с публикации" COM_MYQUESTIONS_SENTTOEXPERT="Отправлен ли вопрос эксперту" COM_MYQUESTIONS_ANSWER="Ответ" COM_MYQUESTIONS_SENTTOAUTHOR="Отправлен ли ответ автору вопроса"
Обратите внимание, что мы не задали перевод для слов "Да" и "Нет", а использовали ключи JYES и JNO, т.к. подобные распространенные слова уже переведены в файле /administrator/language/ru-RU/ru-RU.ini.
Наберите в адресной строке браузера ссылку ссылка: http://localhost/joomla/administrator/index.php?option=com_myquestions&task=reply&cid[]=1. Должна появиться следующая страница (рис. 2.1).
(есть увеличенное изображение)
Рис. 2.1. Фрагмент формы для ответа на вопрос
Сохранение введенных данных
После того, как эксперт напечатал ответ на заданный вопрос и нажал кнопку " Сохранить", необходимо сохранить информацию в базе данных. Прежде всего, создайте две функции – save() и saveQuestion() – в файле admin.myquestions.php:
function save() { $row =& JTable::getInstance('question', 'Table'); if (!$row->bind(JRequest::get('post'))) { echo "n"; exit(); } $row->question = JRequest::getVar('question', '', 'post', 'string', JREQUEST_ALLOWRAW); $row->answer = JRequest::getVar('answer', '', 'post', 'string', JREQUEST_ALLOWRAW); if (!$row->store()) { echo "n"; exit(); } return $row; } function saveQuestion($option, $task) { $row = save(); global $app; if ($task == 'save') $app->redirect('index.php?option='.$option, JText::_('COM_MYQUESTIONS_REPLY_SAVED')); else if ($task == 'apply') $app->redirect('index.php?option='.$option.'&task= reply&cid[]='.$row->id, JText::_('COM_MYQUESTIONS_REPLY_SAVED')); }
Переменной $row присваивается значение экземпляра класса TableQuestion и вызывается функция bind() для связывания переменных, полученных из формы, с полями этого класса.
Для тех значений, которые вводились с помощью редактора Joomla, стандартный способ получения значений из массива JRequest::get('post') не подходит, т.к. функция bind() автоматически удаляет HTML-код, что приведет, в частности, к потере разрывов строк и тегов абзаца. Поэтому для получения значений question и answer в том виде, в котором они были введены в редакторе, используется функция getVar() класса JRequest. Данной функции передается имя переменной формы, значение по умолчанию, метод запроса, с помощью которого мы хотим получить данные (get/post), ожидаемый формат и флаг JREQUEST_ALLOWRAW, означающий, что данные не должны быть отфильтрованы.
Наконец, вызывается функция store() для сохранения вопроса в базе данных.
В функции saveQuestion() происходит вызов функции save(), а затем в зависимости от задачи, т.е. от того, какая кнопка была нажата, – " Сохранить" или " Сохранить и закрыть", – мы перенаправляем пользователя либо к той же странице редактирования вопроса, на которой он находится, но уже с сохраненными данными, либо к главной странице нашего компонента. В обоих случаях выводится сообщение о том, что данные были сохранены. Для перенаправления и вывода сообщения используется функция redirect() глобального объекта JApplication.
Добавьте задачу сохранения записи в переключатель switch() в файле admin.myquestions.php(выделенный код):
Добавьте перевод для ключа COM_MYQUESTIONS_REPLY_SAVED в файл /administrator/language/ru-RU/ru-RU.com_myquestions.ini:
COM_MYQUESTIONS_REPLY_SAVED="Данные сохранены"
Сохраните все ваши файлы и перейдите по ссылке ссылка: http://localhost/joomla/administrator/index.php?option=com_myquestions&task=reply&cid[]=1. Напишите что-нибудь в поле для ответа и нажмите кнопку " Сохранить и закрыть". Вы должны увидеть следующую страницу (рис. 2.2).
(есть увеличенное изображение)
Рис. 2.2. Результат сохранения ответа на вопрос
С помощью phpMyAdmin вы можете проверить, что данные были сохранены в таблице базы данных jos_myquestions (рис. 2.3).
(есть увеличенное изображение)
Рис. 2.3. Ответ на вопрос сохранен в базе данных
Вывод списка записей
Прежде всего, добавьте в файл admin.myquestions.phpследующую функцию:
function showQuestions($option) { $db =& JFactory::getDbo(); $query = "SELECT * FROM #__myquestions"; $db->setQuery($query); $rows = $db->loadObjectList(); if ($db->getErrorNum()) { echo $db->stderr(); return false; } HTML_questions::showQuestions($option, $rows); }
Эта функция загружает все записи из таблицы #__myquestions и передает их в виде массива $rows в следующую функцию, которую необходимо добавить в файл admin.myquestions.html.phpв класс HTML_questions:
function showQuestions($option, &$rows) { $maxlen = 100; ?>
Записи выводятся в таблице, для которой задан CSS-класс adminlist. Все заголовки таблицы, кроме первого, – это обычный текст. Первый заголовок является чекбоксом и используется для одновременного выделения всех отображенных записей.
Затем начинается цикл для вывода самих записей. Значение переменной $k меняется с 0 на 1 и обратно для того, чтобы переключаться между различными классами CSS для четных и нечетных строк, имеющими немного различающиеся свойства фона. С помощью вызова функции JHTML::_('grid.id') мы получаем HTML-код для чекбокса, который будет обрабатываться с помощью JavaScript.
Для каждого вопроса и ответа выводятся первые maxlen символов вместо его текста целиком. При этом с помощью функции strip_tags() отбрасываются теги, чтобы предотвратить ситуацию, когда граница обрезки текста может оказаться внутри тега.
Для перехода к форме ответа на вопрос для каждой записи выводится гиперссылка, которая пропускается через функцию JFilterOutput::ampReplace(), заменяющую амперсанды "&" на коды "&" в соответствии со спецификацией XHTML. Для подключения класса JFilterOutput в код вставлена строка jimport('joomla.filter.output').
Перед закрывающим тегом расположены три скрытых элемента. Option и task были рассмотрены при анализе формы для ответа на вопрос. Значение boxchecked заключается в следующем. Когда пользователь ставит флажок в каком-либо из чекбоксов, значение boxchecked меняется на 1. Значение boxchecked, равное 0, возвращается, когда ни один из чекбоксов не отмечен. С помощью этого значения JavaScript обрабатывает список.
Для обработки случая, когда не выбрано никакой задачи, измените код переключателя switch в файле admin.myquestions.phpследующим образом:
switch($task) { case 'reply': replyToQuestion($option); break; case 'save': case 'apply': saveQuestion($option, $task); break; default: showQuestions($option); break; }
Добавьте в файл /administrator/language/ru-RU/ru-RU.com_myquestions.iniстроку:
COM_MYQUESTIONS_DATE_NOT_DEFINED="Дата не задана"
Теперь при загрузке ссылка: http://localhost/joomla/administrator/index.php?option=com_myquestionsдолжна появиться страница, как на рис. 2.4.
(есть увеличенное изображение)
Рис. 2.4. Список вопросов
Удаление записей
Добавьте следующий оператор case в переключатель switch() в файле admin.myquestions.php:
case 'remove': removeQuestions($option); break;
Также добавьте функцию removeQuestions():
function removeQuestions($option) { global $app; $cid = JRequest::getVar('cid', array(), '', 'array'); $db =& JFactory::getDbo(); if(count($cid)) { $cids = implode(',', $cid); $query = "DELETE FROM #__myquestions WHERE id IN ($cids)"; $db->setQuery($query); if (!$db->query()) { echo "n"; } } $app->redirect('index.php?option=' . $option, JText::_('COM_MYQUESTIONS_QUESTION_DELETED')); }
Если в массиве cid есть элементы, то составляется строка из идентификаторов, разделенных запятыми, которая затем используется для построения запроса удаления соответствующих записей. В данном случае нельзя использовать метод JTable::delete(), т.к. он предназначен для удаления одной записи, а не нескольких.
Добавьте в файл /administrator/language/ru-RU/ru-RU.com_myquestions.iniстроку:
COM_MYQUESTIONS_QUESTION_DELETED="Вопрос(ы) успешно удален(ы)"
Ключевые термины
JDatabase – абстрактный класс, предоставляющий доступ к соединению с базой данных, создающемуся при инициализации приложения Joomla. JDatabaseQuery – класс, методы которого совпадают с ключевыми словами языка SQL и позволяют упростить создание сложных SQL-запросов. JTable – класс, реализующий паттерн Active Record и использующийся для управления таблицами базы данных. Префикс таблиц базы данных – строка, которая присоединяется к названию каждой таблицы Joomla в базе данных. Реальный префикс – то конкретное сочетание символов, которое используется в названиях таблиц базы данных. Связывание – процесс присвоения каждому полю производного от JTable класса значения элемента массива переменных запроса, так что ключ элемента совпадает с названием поля. Символический префикс – сочетание "#__" (решетка и два знака подчеркивания), которое используется в запросах вместо реального префикса.
Краткие итоги
При работе с базой данных различают реальный и символический префиксы. Реальный префикс используется в названиях таблиц базы данных, а символический префикс ("#__") используется в запросах вместо реального префикса. При обработке запроса вместо символического префикса будет автоматически подставлен реальный.
Чтобы выполнить запрос к базе данных Joomla, необходимо осуществить пять операций: получение ссылки на объект JDatabase (абстрактный класс, предоставляющий доступ к соединению с базой данных), формирование запроса, задание запроса, выполнение запроса, загрузка результата.
Запрос может быть сформулирован в виде строки либо разбит на составляющие и построен с помощью методов класса JDatabaseQuery.
Запрос задается для последующего выполнения методом setQuery(), а выполняется либо методом query(), либо, если нам необходимо получить результат, одним из методов для получения форматированного результата: loadResult(), loadRow() и т.д.
Для каждой таблицы, использующейся расширением, необходимо создать класс, производный от JTable. Для каждого поля таблицы необходимо создать одноименное поле этого класса. Производный от JTable класс наследует в числе прочих методы bind(), store(), load() и delete(), позволяющие управлять записями таблицы без единой строки SQL-кода. Когда компонент получает массив переменных запроса, он осуществляет связывание, то есть присваивает каждому полю этого класса значение элемента массива, ключ которого совпадает с названием данного поля.
Существуют методы класса JTable для управления часто используемыми полями ordering, checked_out/checked_out_time, published и hits.
Вопросы
Что такое реальный и символический префиксы?
Какие операции необходимо осуществить для выполнения запроса к базе данных Joomla?
Каким образом может быть сформулирован SQL-запрос?
Какие методы задают и выполняют запрос?
Для чего создается производный от JTable класс?
В чем заключается связывание?
Каким образом осуществляется управления часто используемыми полями?
Упражнения
Адаптируйте код из раздела " Практика" для своего варианта (см. список вариантов в дополнительных материалах).
Генерация элементов HTML (класс JHTML)
Лекция посвящена классу JHTML и поддерживающим классам. Рассмотрены методы для вывода элементов XHTML.
Цель лекции:Изучить готовые методы Joomla для генерации и отображения элементов XHTML и поведений JavaScript.
Основной метод класса JHTML
Joomla содержит методы для генерации и отображения элементов XHTML и поведений JavaScript. Эти методы вызываются с помощью
mixed _(string $type)
Несмотря на то, что в прототипе метода JHTML::_() указан всего один параметр, на практике их, как правило, бывает больше. Они интерпретируются так: по первому параметру метод _() определяет, какой метод необходимо вызвать, а остальные параметры передаются в этот метод.
Параметр $type может быть трех видов:
Название метода самого класса JHTML. Например, $type = 'image' приведет к вызову JHTML::image().
<имя файла>.<имя метода>. Будет вызван метод поддерживающего класса JHTML<Имя файла>.<имя метода>(). В имени поддерживающего класса первая буква <имени файла> станет заглавной. Например, если $type='select.genericlist', то будет вызван метод JHTMLSelect::genericlist().
<префикс>.<имя файла>.<имя метода> и будет вызван метод <префикс>.<Имя файла>.<имя метода>().
Методы класса JHTML
Класс JHTML содержит восемь методов для вывода элементов XHTML.
Поле для ввода даты и пиктограмма, по щелчку на которой появляется календарь
string calendar(string $value, string $name, string $id, string $format = '%Y-%m-%d', array $attribs = null)
где:
$value – значение даты; $name – имя текстового поля; $id – id текстового поля; $format – формат даты; $attribs – дополнительные атрибуты, которые должны быть выведены в теге .
Для примера выведем текущую дату (рис. 3.1):
echo JHTML::_('calendar', date('Y-m-d',time()), 'created', 'created', '%Y-%m-%d', array('size'=>10,'style'=>"class='inputbox'"));
Рис. 3.1. Поле для ввода даты и пиктограмма для вывода календаря
Строка, содержащая дату в заданном формате и часовом поясе
string date(string $input = 'now', string $format = null, mixed $tz = true, bool $gregorian=false)
где:
$input – строка в формате, подходящем для функции date(); $format – формат, к которому необходимо привести дату; $tz – одна из временных зон, поддерживаемых PHP (их список можно найти на странице ссылка: http://www.php.net/manual/ru/timezones.php). Кроме того, $tz может иметь логическое значение: при $tz=true временная зона берется из настроек пользователя, при $tz=false – из настроек сервера; $gregorian – при false для форматирования даты будет использоваться локальный календарь.
Для примера выведем текущую дату:
echo JHTML::_('date',date('Y-m-d',time()), 'Y-m-d h:m', 'Europe/Moscow', false);
Элемент
string iframe(string $url, string $name, array $attribs = null, string $noFrames = '')
где
$url – относительный URL, будущее значение атрибута src; $name – название будущего элемента
Пример:
echo JHTML::_('iframe','index.php', 'myelement', array('width'=>500,'height'=>300), 'Ваш браузер не поддерживает плавающие фреймы');
Элемент
string image(string $file, string $alt, mixed $attribs = null, bool $relative = false, bool $path_only = false)
где
$file – абсолютный или относительный URL изображения; $alt – альтернативный текст; $attribs – ассоциативный массив атрибутов будущего тега (может быть задан сразу в виде строки, например: "width="100%" height="100%""); $relative – перебирать ли варианты пути к файлу; $path_only – возвращать ли только путь к изображению или тег со всеми атрибутами.
Для методов image(), script() и stylesheet() будет выполнена следующая процедура поиска файла. Если $file начинается с «http», то метод просто вернет $file. В противном случае он производит поиск файла, перебирая возможные варианты его названия в зависимости от браузера пользователя. Например, для значения «/pics/pic.png» и браузера Mozilla 5.0 будут перебираться варианты «/pics/pic.png», «/pics/pic_mozilla.png», «/pics/pic_mozilla_5.png», «/pics/pic_mozilla_5_0.png». При $relative=true перебираются также различные варианты пути к файлу в папке текущего шаблона и папке /media. В противном случае метод будет искать файл JPATH_ROOT/<имя файла>для каждого варианта названия файла.
Например, следующий код
echo JHTML::_('image','req.png','Восклицательный знак', array('width'=>25,'height'=>25), true, false);
выведет
Если последним параметром указать true, то эта же строка выведет на экран
/joomla/templates/beez_20/images/req.png
Обратите внимание, что этот путь мы не задавали, его обнаружил метод image().
string link(string $url, string $text, array $attribs = null)
где:
$text – текст ссылки; $attribs – ассоциативный массив атрибутов будущего тега.
Пример:
echo JHTML::_('link','index.php','На главную страницу', array('title'=>'На главную','id'=>'linktomainpage'));
Элемент
mixed script(string $file, bool $framework = false, bool $relative = false, bool $path_only = false, bool $detect_browser = true)
где
$file – путь к файлу; $framework – загружать ли фреймворк Javascript; $path_only – возвращать путь к файлу или добавить все найденные файлы к текущему документу; $detect_browser – определять ли браузер пользователя для включения файлов Javascript для этого браузера.
При $path_only=false метод не возвращает никакого значения.
Пример:
echo JHTML::_('script', 'media/system/js/calendar.js', false, false, true, false);
Элемент
mixed stylesheet(string $file, array $attribs = array(), bool $relative = false, bool $path_only = false, bool $detect_browser = true)
Все параметры аналогичны рассмотренным выше.
Пример:
echo JHTML::_('stylesheet', 'media/system/css/system.css', array("title"=>"Название стиля","media"=>"screen, print"), false, true, false);
Всплывающая подсказка
string tooltip(string $tooltip, mixed $title = '', string $image = 'tooltip.png', string $text = '', string $href = '', string $alt = 'Tooltip', string $class = 'hasTip')
где
$tooltip – текст подсказки; $title – название подсказки или ассоциативный массив с ключами title, image, text, href, alt и соответствующими значениями; $image – изображение, для которого будет выводиться подсказка (если не задано значение $text); $text – текст, для которого будет выводиться подсказка (если не задано значение $image); $href – URL, на который будет произведен переход по щелчку на изображение или текст; $alt – значение атрибута alt тега ; $class – название класса элемента , в который будет заключен тег .
Изображение с подсказкой:
echo JHTML::tooltip('Текст подсказки', 'Заголовок подсказки', 'tooltip.png', '', 'http://www.mysite.ru');
Текст с подсказкой:
echo JHTML::tooltip('Текст подсказки', 'Заголовок подсказки', '', 'Наведите на этот текст курсор мыши, чтобы увидеть подсказку');
Поддерживающие классы
Рассмотрим некоторые методы поддерживающих классов. Полный список этих методов можно найти в документации, однако на текущий момент она не достаточно полная и содержит ошибки, поэтому для детальной справки по какому-либо методу вы можете обратиться напрямую к исходным кодам в папке /libraries/joomla/html/html.
JHTMLBehavior
Методы этого класса загружают код Javascript в заголовок документа. Методы JHTMLBehavior позволяют вывести календарь, дерево элементов, файловый загрузчик и некоторые другие элементы управления. Рассмотрим один из методов, позволяющий вывести всплывающее модальное окно без перезагрузки страницы:
void modal(string $selector = 'a.modal', array $params = array())
где
$selector – селектор класса; $params – массив параметров, ключи которого могут быть следующими: ajaxOptions, size, shadow, onOpen, onClose, onUpdate, onResize, onShow, onHide.
В следующем примере выводятся две ссылки. При нажатии на первую из них появляется всплывающее окно с изображением, на вторую – с веб-страницей.
Щелкните, чтобы увидеть изображение
Щелкните, чтобы открылось окно с веб-страницей
Первое окно выглядит так, как на рис. 3.2.
(есть увеличенное изображение)
Рис. 3.2. Модальное окно
JHTMLEmail
Содержит один метод для скрытия адреса электронной почты в целях его защиты от спам-ботов:
string cloak(string $mail, bool $mailto=1, string $text='', bool $email=1)
где
$mail – e-mail; $mailto – выводить ли e-mail в виде ссылки … или в виде текста; $text – текст этой ссылки; $email – является ли $text адресом электронной почты.
Пример:
echo JHtml::_('email.cloak', 'admin@mysite.ru', 1, 'Написать администратору', 0);
JHTMLForm
Содержит один метод, который возвращает код скрытого поля формы для уменьшения риска CSRF-атак: string token()
Именем получившегося элемента формы станет сгенерированная случайным образом строка, которая используется для проверки того, что запрос был сделан из конкретных формы и сессии.
Для предотвращения CSRF-атак вставляйте в каждую форму своего компонента строку:
JHTMLGrid
Методы данного класса используются для вывода в таблице в панели управления таких элементов, как чекбокс, пиктограмма для переключения состояния " опубликовано"/"не опубликовано", для отображения заголовка столбца как ссылки для сортировки по этому столбцу и др.
Таблица должна располагаться внутри формы под названием adminForm, обязательно включающей два скрытых поля: boxchecked со значением по умолчанию 0 и task.
Для создания чекбокса используется метод
mixed id(int $rowNum, int $recId, bool $checkedOut=false, string $name='cid')
где
$rowNum – номер строки в таблице; $recId – id записи; $checkedOut – отмечен ли элемент; $name – имя элемента формы.
Метод возвращает html-код чекбокса, если элемент не отмечен, и пустую строку в противном случае.
Для создания пиктограммы, по щелчку на которой можно изменять значение поля published с 0 на 1 и обратно, используется
string published(mixed $value, int $i, string $img1 = 'tick.png', string $img0 = 'publish_x.png', string $prefix='')
где
$value – объект или только значение поля published; $i – номер строки в таблице; $img1 – изображение при published = 1; $img0 – изображение при published = 0; $prefix – префикс, который будет добавлен к названиям по умолчанию задач publish/unpublish.
Для примера выведем элементы массива $rows как строки таблицы, добавив для каждой записи ячейки с чекбоксом и значком «опубликовано»/"не опубликовано":
$k = 0; for ($i = 0, $n = count($rows); $i < $n; $i ++) { $row = &$rows[$i]; ?>