Пошаговое руководство по созданию блоков

Moodle
Демонстрационный сайт Moodle
Тип система управления обучением
Разработчик Martin Dougiamas
ОС Cross-platform
Лицензия GNU GPL
Сайт moodle.org
Источник: docs.moodle.org
Автор источника: Jon Papaioannou (pj@moodle.org).
Перевод: Васин Юрий (george.a.wise@gmail.com).

Для опытных разработчиков будет полезнее ознакомиться с приложением А, которое содержит справочную информацию о классе block_base.

Введение править

Блоки - это стандартные контейнеры для отображения виджетов на страницах Moodle. В этом руководстве мы рассмотрим несуществующий блок "SimpleHTML". Подразумевается, что вcе пути начинаются из домашней директории Moodle.

Блоки создаются как набор пользовательских скриптов в директории с именем блока. Эта директория при установке помещается в стандартную директорию Moodle для пользовательских блоков /blocks/. Основной скрипт блока block_nameofblock.php (имя блока вместо nameofblock) содержит пользовательский класс, который является расширением базового класса block_base.

Здравствуй Мир править

Для создания блока в Moodle в большинстве случаев достаточно написать один скрипт. Для начала в директории blocks/имя_блока/ создаем наш скрипт имя_блока. Например если наш блок будет носить имя simplehtml, путь к скрипту будет иметь вид /blocks/simplehtml/block_simplehtml.php. Теперь начнем писать сам код:

<?php
class block_simplehtml extends block_base
{
  function init()
  {
    $this->title   = get_string('simplehtml', 'block_simplehtml');
    $this->version = 2004111200;
  }
   
}

Сначала мы объявляем класс, он должен обязательно объявлятся таким образом как показано, т. к. является расширением автоподключаемого класса, который находится в файле /blocks/moodleblock.class.php В дальнейшем мы можем (и даже должны) изменять только часть simplehtml, все остальное является стандартным и стандартизированным.

Первый метод в нашем классе init() обязателен для всех блоков и служит для определения двух методов. Рассмотрим их более подробно.

  • $this->title это заголовок, отображаемый в строке заголовка нашего блока. Мы можем назвать его как угодно. В нашем случае мы берем заголовок из языкового файла, который прилагается к нашему блоку. Более подробно мы рассмотрим этот метод позже. Если вы хотите использовать блок без заголовка, назначьте методу любое значение, но не пустую строку! Далее мы рассмотрим как отключить отображение заголовка.
  • $this->version это версия нашего блока. Используется скриптом обновления (англ. upgrade script). В нашем случае мы установили версию как дату ГГГГММДД00, для простоты.

Вывод править

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

  
  function get_content()
  {
    if ($this->content !== NULL) {
      return $this->content;
    }

    $this->content         =  new stdClass;
    $this->content->text   = 'Здороваемся с Миром :)';
    $this->content->footer = 'Завершающий вывод...';
 
    return $this->content;
  }
}   // Конец класса
?>

Давайте проанализируем этот метод, чтобы увидеть, что происходит.

Прежде всего, мы должны произвести вывод $this->content только в том случае, если оно не равно NULL, в противном случае сформируем content. Это делается для экономии ресурсов и ускорения обработки блоков. Мы можем выводить HTML как в text, так и в footer.

На этом этапе наш блок уже может быть автоматически установлен в систему Moodle. Открываем страницу администратора, нажимаем Уведомления в блоке Администрирование и наш блок появляется на главной странице.

Конфигурирование править

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

function instance_allow_config() {
  return true;
}

Этого достаточно для того чтобы в системе Moodle появился пункт (иконка) "Настроить" для нашего блока. Но если вы попробуете его настроить у вас ничего не получится, нам необходимо описать что и как конфигурировать. Для этого нам необходимо создать еще один файл /blocks/simplehtml/config_instance.html (должен называться именно так) с следующим содержанием:

<table cellpadding="9" cellspacing="0">
  <tr valign="top">
    <td align="right">
       <?php print_string('configcontent', 'block_simplehtml'); ?>:
    </td>
    <td>
       <?php print_textarea(true, 10, 50, 0, 0, 'text', $this->config->text); ?>
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <input type="submit" value="<?php print_string('savechanges') ?>" />
    </td>
  </tr>
</table>

<?php use_html_editor(); ?>

Легко увидеть, что код выше предоставляет нам визуальный редактор текста для нашего блока с кнопкой сохранения. Мы можем обращаться к свойствам класса как $this->config->свойство и менять их из конфигурационной формы.

Вы также наверное заметили, что мы можем использовать любые элементы формы, включая кнопки и их значения будут переданы в скрипт как $this->config->свойство и их можно использовать в любом месте кроме метода init(). При этом нет необходимости открывать и закрывать форму дескрипторами <form>, всю грязную работу сделает Moodle.

Теперь нам осталось только привязать наш конфигурационный файл к нашему блоку. Сделать это довольно просто, в фале /blocks/simplehtml/block_simplehtml.php находим:

$this->content         =  new stdClass;
$this->content->text   = 'Здороваемся с Миром :)';
$this->content->footer = 'Завершающий вывод...';

и заменяем на:

$this->content = new stdClass;
$this->content->text   = $this->config->text;
$this->content->footer = '';

Как вы заметили мы ничего не выводим с помощью $this->content->footer, потому что в нашем случае нам просто нечего выводить в нижний завершающий блок.

Заголовок (specialization) править

Давайте теперь пойдем дальше и дадим возможность пользователям менять не только текст внутри нашего блока но и его заголовок. Для этого добавим еще один параметр в наш конфигурационный файл /blocks/simplehtml/config_instance.html:

<tr valign="top">
  <td align="right"><p>
    <?php print_string('configtitle', 'block_simplehtml'); ?>:</p>
  </td>
  <td>
    <input type="text" name="title" size="30" value="<?php echo $this->config->title; ?>" />
  </td>
</tr>

Теперь мы можем использовать параметр $this->config->title, но нам он необходим в методе init(), а как мы говорили раньше обращаться к конфигурационным данным в этом методе нельзя. Как же быть? Для решения этой проблемы нам понадобится еще один специальный метод:

function specialization()
{
  if(!empty($this->config->title)){
    $this->title = $this->config->title;
  }else{
    $this->config->title = 'Заголовок по умолчанию ...';
  }
  if(empty($this->config->text)){
    $this->config->text = 'Текст по умолчанию ...';
  }    
}

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

"Прятки" править

Теперь мы всегда сможем видеть наш блок на страницах moodle. Оказывается, что не всегда. Бывают такие случаи, когда блок вообще нет смысла показывать. Что будет отображать блок "Последние действия", если в последнее время не было никаких действий. В moodle любой блок будет скрыт если он ничего не содержит, т. е. если $this->content->text и $this->content->footer не содержат никаких значений. При обработке блока каждый раз вызывается метод is_empty(), который и проверяет необходимость его отображения.

Заметьте, что заголовок не имеет никакого значения. Блок считается пустым, если в его теле пусто.

Множественные включения править

Иногда в рамках одного курса необходимо использовать несколько одинаковых блоков (одного типа). Обеспечить возможность включения нескольких блоков на одной странице в moodle очень легко. Для этого необходим еще один короткий метод:

function instance_allow_multiple()
{
  return true;
}

Теперь количество одинаковых блоков на странице не ограничено. Но стоит помнить, что несмотря на это администратор может запретить множественные вхождения для любого блока вручную, используя пункт модули → блоки → управление блоками на панели администрирования.

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

«Глобализация» править

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

function has_config()
{
  return true;
}

Для этого метода необходим соответствующий файл для отображения самих настроек, он должен называться /blocks/simplehtml/config_global.html. В нашем случае в нем будет одна опция «разрешить HTML»:

<div style="text-align: center;">
 <input type="hidden" name="block_simplehtml_strict" value="0" />
 <input type="checkbox" name="block_simplehtml_strict" value="1"
   <?php if(!empty($CFG->block_simplehtml_strict)) 
             echo 'checked="checked"'; ?> />
   <?php print_string('donotallowhtml', 'block_simplehtml'); ?>
 <p>
 <input type="submit" value="<?php print_string('savechanges'); ?>" />
 </p>
</div>

Вы наверное заметили два поля с одинаковым именем block_simplehtml_strict, одно из которых скрытое. Скрытое поле гаранитирует передачу переменной в наш скрипт в случае когда checkbox находится в состоянии unchecked (пустой). При обработке формы пустой checkbox вообще не передается в обрабатывающий скрипт. А при попытке передать две переменных с одинаковым именем сохранится ее самое последнее значение.

Теперь можно проверять глобальную настройку используя конструкцию if(!empty($CFG->block_simplehtml_strict)). Использование функции empty() помогает нам обрабатывать как false оба случая, когда переменная не задана вообще и когда она равна нулю.

config_save() править

Есть более сложный способ получить и сохранить конфигурационные данные. Он реализуется с помощью метода config_save(), синтаксис которого показан ниже:

function config_save($data)
{
  // Основное назначение - сохранить все переменные в свойствах $CFG
  foreach ($data as $name => $value)
  {
    set_config($name, $value);
  }
  return true;
}

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

function config_save($data)
{
  if(isset($data['block_simplehtml_strict'])) {
    set_config('block_simplehtml_strict', '1');
  }else {
    set_config('block_simplehtml_strict', '0');
  }
  return true;
}

чтение конфигурации править

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

$string = $CFG->configsetting;

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

print_object($CFG);

instance_config_save() править

Если у нас есть несколько однотипных блоков, то мы можем задать для них глобальные свойства. А как сохранить конфигурацию каждого из них? Для этого существует метод instance_config_save() который по умолчанию выглядит так:

function instance_config_save($data)
{
  $data = stripslashes_recursive($data); // Экранируем спецсимволы
  $this->config = $data;
  return set_field('block_instance', 
                   'configdata',
                    base64_encode(serialize($data)), // кодируем и сериализуем
                   'id', 
                   $this->instance->id);
}

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

function instance_config_save($data)
{
  // Обработка (очистка) данных
  global $CFG;
  if(!empty($CFG->block_simplehtml_strict)) {
    $data->text = strip_tags($data->text);
  }
 
  // Теперь перенаправляем данные на обработку в родительский метод (на сохранение)
  return parent::instance_config_save($data);
}

Дополнительные функции править

Рассмотрим методы которые позволяют настроить и изменить внешний вид блоков.

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

function hide_header()
{
  return true;
}

Как мы уже говорили выше, мы не можем просто указать в качестве заголовка пустую строку внутри метода init(). Заголовок используется для идентификации блоков.

Возможно вы захотите указать для вашего блока ширину. В Moodle сделать это напрямую нельзя, но возможно запросить предпочитаемую ширину, при этом фактическая ширина будет стремится к предпочитаемой. Фактическая ширина блока, зависит от ширины других блоков, текущей темы оформления и других факторов. Для примера, стандартные блоки moodle гарантированно прорисовывают запрос ширины в диапазоне от 180 до 210 пикселей (включительно).

Для того чтобы сообщить Moodle предпочитаемую ширину для нашего блока, используется следующий метод:

function preferred_width()
{
  // Предпочитаемое значение в пикселях
  return 200;
}

Все блоки заключены в <div> (<table> в более старых версиях) контейнеры, атрибуты и CSS свойства которых мы можем изменять. Целесообразнее для блока создать CSS класс и прописать селектор с свойствами в CSS файле темы Moodle. Для этого нам необходимо использовать соответствующий метод, который возвращает ассоциативный массив атрибутов и значений:

function html_attributes()
{
  return array(
    'class'       => 'sideblock block_'. $this->name(),
    'onmouseover' => "alert('На блок наведена мышь!');"
  );
}

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

полезные примеры править

function html_attributes()
{
    // По умолчанию, генерируем уникальный id и имя CSS класса
    return array('id' => 'inst'.$this->instance->id, 'class' => 'block_'. $this->name());
}

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

function html_attributes()
{
    $attrs = parent::html_attributes();
    // Здесь добавляем свои атрибуты, например
    // $attrs['width'] = '50%';
    return $attrs;
}

«Паранджа» править

Трудно представить себе блок который был бы полезен во всех случаях, на всех страницах Moodle. Поэтому Moodle позволяет определить на каких страницах, в рамках каких курсов показывать блок. Для этого используется специальный метод, который возвращает ассоциативный массив ключи которого задают формат страниц, а значения (true/false) определяют показывать блок или нет:

function applicable_formats()
{
  return array(
           'course-view' => true);
}

В результате использования этого метода блок будет отображаться только на страницах курсов.

Форматы страниц позволяют указывать страницу или тип страницы не указывая имя скрипта, который отвечает за ее отображение. Например, если мы хотим указать курс который отображается скриптом /course/view.php, мы используем формат course-view. Для тестов mod-quiz-view. Но есть несколько особенностей использования шаблонов:

  1. Имя главной страницы Moodle — site-index;
  2. Формат(шаблон) имени курса не только course-view, он также включает course-view-weeks, course-view-topics и т. д.;
  3. Для указания всех страниц используется шаблон all;
  4. Для указания группы страниц можно использовать общую для них приставку (префикс). Напимер mod затронет все страницы модулей. course-view затронет все курсы, независимо от их содержания. И наконец site затронет главную страницу (т. к. полный шаблон этой страницы site-index);
  5. В шаблонах допускается использование символа * для обозначения любого слова (англ. wildcards). Например, mod и mod-* определяют одни и те же страницы;
  6. Порядок определения шаблонов не имеет значения.

Мы можем использовать столько шаблонов, сколько захотим. Каждый шаблон может запрещать или разрешать отображение блока.

function applicable_formats()
{
  return array('site' => true);
}

В этом случае блок будет отображаться только на главной странице Moodle. Так как шаблон all не указан, то отображение блока будет запрещено. Но шаблон site разрешает отображение для главной страницы.

Ссылки править