3. Summary
Introduction
➔
Part A
➔
1) Presenting 2 Plugin's Example
➔
2) Deeper Analysis of the 2 plugins
➔
Part B
➔
1) General Plugin Pattern-Model
➔
2) Simple Plugin Creation example
➔
Conclusion
➔
7. Where does Chamilo
come from?
Claroline
Dokeos
Dokeos
Latinoamérica
2001
2004
2007
1.0
Chamilo LMS
1.8
2010
Chamilo LMS
1.9
2012
8. Chamilo 1.9.6 still is...
A Learning Management System
➔
A system to help manage learning.
➔
A system to help to manage
knowledge
➔
Improves informal learning eficiency
➔
Improves learning monitoring
➔
Improves the way documents are kept
➔
Improves availability of courses
➔
Reduces costs and training times
➔
9. Part A
1) Presenting 2 Plugin's Example
➔
Show user information Plugin
➔
RSS Plugin
➔
2) Deeper Analysis of the 2 plugins
➔
10. Part A / 1
Plugin Examples
Show user information Plugin
➔
RSS Plugin
➔
11. Part A / 1
Plugin Examples
Administration Panel
12. Part A / 1
Plugin Examples
Administration Panel / Plugin SubPanel
59. Part B / 1 Settings.lib.php
<?php
/* For licensing terms, see /license.txt */
….....
/**
* This function allows easy activating and inactivating of regions
* @author Julio Montoya <gugli100@gmail.com> Beeznest 2012
*/
function handle_regions() {
…........
}
$plugin_obj = new AppPlugin();
$possible_plugins = $plugin_obj->read_plugins_from_path();
$installed_plugins = $plugin_obj->get_installed_plugins();
if (!empty($installed_plugins)) {
$not_installed = array_diff($possible_plugins, $installed_plugins);
} else {
$not_installed = $possible_plugins;
}
echo '<form name="plugins" method="post" action="'.api_get_self().'?category='.Security::remove_XSS($_GET['category']).'">';
echo '<table class="data_table">';
echo '<tr>';
echo '<th width="400px">';
echo get_lang('Plugin');
echo '</th><th>';
echo get_lang('Regions');
…......
60. Part B / 1 Settings.lib.php
…...
/* We display all the possible plugins and the checkboxes */
$plugin_region_list = array();
$my_plugin_list = $plugin_obj->get_plugin_regions();
foreach ($my_plugin_list as $plugin_item) {
$plugin_region_list[$plugin_item] = $plugin_item;
}
….....
61. Part B / 1 Settings.lib.php
…......
/**
* This function allows easy activating and inactivating of plugins
….....
function handle_plugins() {
$plugin_obj = new AppPlugin();
if (isset($_POST['submit_plugins'])) {
store_plugins();
// Add event to the system log.
$user_id = api_get_user_id();
$category = $_GET['category'];
event_system(LOG_CONFIGURATION_SETTINGS_CHANGE,
LOG_CONFIGURATION_SETTINGS_CATEGORY, $category, api_get_utc_datetime(),
$user_id);
Display :: display_confirmation_message(get_lang('SettingsStored'));
}
$all_plugins = $plugin_obj->read_plugins_from_path();
$installed_plugins = $plugin_obj->get_installed_plugins();
…......
$plugin_list = array();
$my_plugin_list = $plugin_obj->get_plugin_regions();
foreach($my_plugin_list as $plugin_item) {
$plugin_list[$plugin_item] = $plugin_item;
}
63. Part B / 1 Settings.lib.php
…..
function store_regions() {
$plugin_obj = new AppPlugin();
// Get a list of all current 'Plugins' settings
$installed_plugins = $plugin_obj->get_installed_plugins();
$shortlist_installed = array();
if (!empty($installed_plugins)) {
foreach ($installed_plugins as $plugin) {
if (isset($plugin['subkey'])) {
$shortlist_installed[] = $plugin['subkey'];
}
}
}
$shortlist_installed = array_flip(array_flip($shortlist_installed));
$plugin_list = $plugin_obj->read_plugins_from_path();
foreach ($plugin_list as $plugin) {
if (isset($_POST['plugin_'.$plugin])) {
$areas_to_installed = $_POST['plugin_'.$plugin];
if (!empty($areas_to_installed)) {
$plugin_obj->remove_all_regions($plugin);
foreach ($areas_to_installed as $region) {
if (!empty($region) && $region != '-1' ) {
$plugin_obj->add_to_region($plugin, $region);
}
}
….......
64. Part B / 1 Settings.lib.php
…..
/**
* This function allows easy activating and inactivating of plugins
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
*/
function store_plugins() {
$plugin_obj = new AppPlugin();
// Get a list of all current 'Plugins' settings
$plugin_list = $plugin_obj->read_plugins_from_path();
$installed_plugins = array();
foreach ($plugin_list as $plugin) {
if (isset($_POST['plugin_'.$plugin])) {
$plugin_obj->install($plugin);
$installed_plugins[] = $plugin;
}
}
if (!empty($installed_plugins)) {
$remove_plugins = array_diff($plugin_list, $installed_plugins);
} else {
$remove_plugins = $plugin_list;
}
foreach ($remove_plugins as $plugin) {
$plugin_obj->uninstall($plugin);
}
}
/**
….......
65. Part B / 1 Settings.lib.php
…..
function generate_settings_form($settings, $settings_by_access_list) {
global $_configuration, $settings_to_avoid, $convert_byte_to_mega_list;
$table_settings_current = Database :: get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
$form = new FormValidator('settings', 'post', 'settings.php?category='.Security::remove_XSS($_GET['category']));
$form->addElement('hidden', 'search_field', (!empty($_GET['search_field'])?
Security::remove_XSS($_GET['search_field']):null));
$url_id = api_get_current_access_url_id();
if (!empty($_configuration['multiple_access_urls']) && api_is_global_platform_admin() && $url_id == 1) {
$group = array();
$group[] = $form->createElement('button', 'mark_all', get_lang('MarkAll'));
$group[] = $form->createElement('button', 'unmark_all', get_lang('UnmarkAll'));
$form->addGroup($group, 'buttons_in_action_right');
…...
67. Part B / 1 Settings.php
<?php
/* For licensing terms, see /license.txt */
/**
* With this tool you can easily adjust non critical configuration settings.
* Non critical means that changing them will not result in a broken campus.
*
* @author Patrick Cool
* @author Julio Montoya - Multiple URL site
* @package chamilo.admin
*/
…........
…....
// Database table definitions.
$table_settings_current = Database :: get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
// Setting breadcrumbs.
$interbreadcrumb[] = array('url' => 'index.php', 'name' => get_lang('PlatformAdmin'));
// Setting the name of the tool.
$tool_name = get_lang('PlatformConfigSettings');
if (empty($_GET['category'])) {
$_GET['category'] = 'Platform';
}
…....
68. Part B / 1 Settings.php
…..
$url_id = api_get_current_access_url_id();
$settings = null;
function get_settings($category = null) {
$url_id = api_get_current_access_url_id();
$settings_by_access_list = array();
if ($url_id == 1) {
$settings = api_get_settings($category, 'group', $url_id);
} else {
$url_info = api_get_access_url($url_id);
…......
// One more validation if is changeable.
if ($row['access_url_changeable'] == 1)
$settings_by_access_list[ $row['variable'] ] [ $row['subkey'] ] [ $row['category'] ] = $row;
else
$settings_by_access_list[ $row['variable'] ] [ $row['subkey'] ] [ $row['category'] ] = array();
}
}
}
if (isset($category) && $category== 'search_setting') {
if (!empty($_REQUEST['search_field'])) {
$settings = search_setting($_REQUEST['search_field']);
}
}
return array('settings' => $settings, 'settings_by_access_list' => $settings_by_access_list);
}
// Build the form.
….....
73. Part B / 1 Config_plugin.php
<?php
/* For licensing terms, see /license.txt */
/............
// name of the language file that needs to be included
$language_file = array ('registration','admin');
$cidReset = true;
require_once '../inc/global.inc.php';
// Access restrictions
api_protect_admin_script();
$plugin_name = $_GET['name'];
$plugin_obj = new AppPlugin();
$plugin_info = $plugin_obj->get_plugin_info($plugin_name, true);
if (empty($plugin_info)) {
api_not_allowed();
}
$installed_plugins = $plugin_obj->get_installed_plugins();
if (!in_array($plugin_name, $installed_plugins)) {
api_not_allowed();
}
global $_configuration;
74. Part B / 1 Config_plugin.php
$content = null;
if (isset($plugin_info['settings_form'])) {
$form = $plugin_info['settings_form'];
if (isset($form)) {
//We override the form attributes
…........
}
} else { $message = Display::return_message(get_lang('NoConfigurationSettingsForThisPlugin'), 'warning');
}
if (isset($form)) {
if ($form->validate()) {
$values = $form->exportValues();
//api_delete_category_settings_by_subkey($plugin_name);
$access_url_id = api_get_current_access_url_id();
api_delete_settings_params(array('category = ? AND access_url = ? AND subkey = ? AND type = ? and variable
<> ?' =>
array('Plugins', $access_url_id, $plugin_name, 'setting', "status")));
foreach ($values as $key => $value) {
$key = Database::escape_string($plugin_name.'_'.$key);
api_add_setting($value, $key, $plugin_name, 'setting', 'Plugins', $plugin_name, null, null, null,
$_configuration['access_url'], 1);
}
$message = Display::return_message(get_lang('Updated'), 'success');
}
}
$tpl = new Template($tool_name, true, true, false, true, false);
$tpl->assign('actions', $actions);
$tpl->assign('message', $message);
$tpl->assign('content', $content);
$tpl->display_one_col_template();
76. Part B / 1 Plugin.class.php
<?php
/* For licensing terms, see /license.txt */
/**
* Base class for plugins
*
* This class has to be extended by every plugin. It defines basic methods
…....
*/
class Plugin {
protected $version = '';
protected $author = '';
protected $fields = array();
private $settings = null;
private $strings = null; //translation strings
public $is_course_plugin = false;
/**
* When creating a new course, these settings are added to the course, in
* the course_info/infocours.php
* To show the plugin course icons you need to add these icons:
* main/img/icons/22/plugin_name.png
* main/img/icons/64/plugin_name.png
* main/img/icons/64/plugin_name_na.png
* @example
* $course_settings = array(
array('name' => 'big_blue_button_welcome_message', 'type' => 'text'),
array('name' => 'big_blue_button_record_and_store', 'type' => 'checkbox')
);
*/
….....
77. Part B / 1 Plugin.class.php
….
public $course_settings = array();
/**
* This indicates whether changing the setting should execute the callback
* function.
*/
public $course_settings_callback = false;
/**
* Default constructor for the plugin class. By default, it only sets
* a few attributes of the object
* @param string Version of this plugin
* @param string Author of this plugin
* @param array Array of global settings to be proposed to configure the
plugin
* @return void
*/
protected function __construct($version, $author, $settings = array()) {
$this->version = $version;
$this->author = $author;
$this->fields = $settings;
global $language_files;
$language_files[] = 'plugin_' . $this->get_name();
}
/**
…..
78. Part B / 1 Plugin.class.php
…
/**
* Gets an array of information about this plugin (name, version, ...)
* @return array Array of information elements about this plugin
*/
function get_info() {
$result = array();
$result['title']
= $this->get_title();
$result['comment']
= $this->get_comment();
$result['version']
= $this->get_version();
$result['author']
= $this->get_author();
$result['plugin_class'] = get_class($this);
$result['is_course_plugin'] = $this->is_course_plugin;
if ($form = $this->get_settings_form()) {
$result['settings_form'] = $form;
foreach ($this->fields as $name => $type) {
$value = $this->get($name);
$result[$name] = $value;
}
}
return $result;
}
/**
* Returns the "system" name of the plugin in lowercase letters
* @param string Name of the plugin
*/
function get_name() {
$result = get_class($this);
$result = str_replace('Plugin', '', $result);
$result = strtolower($result);
return $result;
}
/**
….
79. Part B / 1 Plugin.class.php
…
/**
* Returns the title of the plugin
* @param string Title of the plugin
*/
function get_title() {
return $this->get_lang('plugin_title');
}
/**
* Returns the description of the plugin
* @param string Description of the plugin
*/
function get_comment() {
return $this->get_lang('plugin_comment');
}
/**
* Returns the version of the plugin
* @param string Version of the plugin
*/
function get_version() {
return $this->version;
}
/**
* Returns the author of the plugin
* @param string Author(s) of the plugin
*/
function get_author() {
return $this->author;
}
….
80. Part B / 1 Plugin.class.php
…
/**
* Returns the contents of the CSS defined by the plugin
* @param string The CSS string
*/
function get_css() {
$name = $this->get_name();
$path = api_get_path(SYS_PLUGIN_PATH)."$name/resources/$name.css";
if (!is_readable($path)) {
return '';
}
$css = array();
$css[] = file_get_contents($path);
$result = implode($css);
return $result;
}
/**
* Returns an HTML form (generated by FormValidator) of the plugin settings
* @return string FormValidator-generated form
*/
function get_settings_form() {
$result = new FormValidator($this->get_name());
$defaults = array();
foreach ($this->fields as $name => $type) {
$value = $this->get($name);
$defaults[$name] = $value;
$type = isset($type) ? $type : 'text';
$help = null;
if ($this->get_lang_plugin_exists($name.'_help')) {
$help = $this->get_lang($name.'_help');
}
switch ($type) {
….
81. Part B / 1 Plugin.class.php
…
/**
* Returns the value of a given plugin global setting
* @param string Name of the plugin
* @return string Value of the plugin
*/
function get($name) {
$settings = $this->get_settings();
foreach ($settings as $setting) {
if ($setting['variable'] == ($this->get_name() . '_' . $name)) {
return $setting['selected_value'];
}
}
return false;
}
/**
* Returns an array with the global settings for this plugin
* @return array Plugin settings as an array
*/
public function get_settings() {
if (is_null($this->settings)) {
$settings = api_get_settings_params(array("subkey = ? AND category = ? AND type = ? " =>
array($this->get_name(), 'Plugins', 'setting')));
$this->settings = $settings;
}
return $this->settings;
}
….
82. Part B / 1 Plugin.class.php
…
/**
* Tells whether language variables are defined for this plugin or not
* @param string System name of the plugin
* @return boolean True if the plugin has languag variables defined, false otherwise
*/
public function get_lang_plugin_exists($name) {
return isset($this->strings[$name]);
}
/**
* Hook for the get_lang() function to check for plugin-defined language terms
* @param string Name of the language variable we are looking for
* @return string The translated language term of the plugin
*/
public function get_lang($name) {
// Check whether the language strings for the plugin have already been
// loaded. If so, no need to load them again.
if (is_null($this->strings)) {
global $language_interface;
$root = api_get_path(SYS_PLUGIN_PATH);
$plugin_name = $this->get_name();
//1. Loading english if exists
$english_path = $root.$plugin_name."/lang/english.php";
if (is_readable($english_path)) {
include $english_path;
$this->strings = $strings;
}
….
83. Part B / 1 Plugin.class.php
…
/**
* Caller for the install_course_fields() function
* @param int The course's integer ID
* @param boolean Whether to add a tool link on the course homepage
* @return void
*/
function course_install($course_id, $add_tool_link = true) {
$this->install_course_fields($course_id, $add_tool_link);
}
/**
* Add course settings and, if not asked otherwise, add a tool link on the course homepage
* @param int Course integer ID
* @param boolean Whether to add a tool link or not (some tools might just offer a configuration
section and act on the backend)
* @return boolean False on error, null otherwise
*/
public function install_course_fields($course_id, $add_tool_link = true) {
$plugin_name = $this->get_name();
$t_course = Database::get_course_table(TABLE_COURSE_SETTING);
….
85. Part B / 1 Plugin.lib.php
<?php
/* See license terms in /license.txt */
class AppPlugin {
var $plugin_regions = array (
//
'loginpage_main',
'login_top',
'login_bottom',
'menu_top',
'menu_bottom',
/*
'campushomepage_main',
'campushomepage_menu',
'mycourses_main',
'mycourses_menu',*/
'content_top',
'content_bottom',
'header_main',
'header_center',
'header_left',
'header_right',
//'footer',
'footer_left',
'footer_center',
'footer_right',
'course_tool_plugin'
);
…...
86. Part B / 1 Plugin.lib.php
…...
function __construct() {
}
{
function read_plugins_from_path() {
/* We scan the plugin directory. Each folder is a potential plugin. */
$pluginpath = api_get_path(SYS_PLUGIN_PATH);
$possible_plugins = array();
$handle = @opendir($pluginpath);
while (false !== ($file = readdir($handle))) {
if ($file != '.' && $file != '..' && is_dir(api_get_path(SYS_PLUGIN_PATH).$file))
$possible_plugins[] = $file;
}
}
}
@closedir($handle);
sort($possible_plugins);
return $possible_plugins;
function get_installed_plugins_by_region(){
$used_plugins = array();
/* We retrieve all the active plugins. */
$result = api_get_settings('Plugins');
foreach ($result as $row) {
$used_plugins[$row['variable']][] = $row['selected_value'];
}
return $used_plugins;
}
….
87. Part B / 1 Plugin.lib.php
…...
function get_installed_plugins() {
$installed_plugins = array();
$plugin_array = api_get_settings_params(array("variable = ? AND selected_value = ? AND category = ? " =>
array('status', 'installed', 'Plugins')));
}
if (!empty($plugin_array)) {
foreach ($plugin_array as $row) {
$installed_plugins[$row['subkey']] = true;
}
$installed_plugins = array_keys($installed_plugins);
}
return $installed_plugins;
function install($plugin_name, $access_url_id = null) {
if (empty($access_url_id)) {
$access_url_id = api_get_current_access_url_id();
} else {
$access_url_id = intval($access_url_id);
}
api_add_setting('installed', 'status', $plugin_name, 'setting', 'Plugins', $plugin_name, null, null, null, $access_url_id, 1);
//api_add_setting($plugin, $area, $plugin, null, 'Plugins', $plugin, null, null, null, $_configuration['access_url'], 1);
$pluginpath = api_get_path(SYS_PLUGIN_PATH).$plugin_name.'/install.php';
}
….
if (is_file($pluginpath) && is_readable($pluginpath)) {
//execute the install procedure
require $pluginpath;
}
88. Part B / 1 Plugin.lib.php
…...
function uninstall($plugin_name, $access_url_id = null) {
if (empty($access_url_id)) {
$access_url_id = api_get_current_access_url_id();
} else {
$access_url_id = intval($access_url_id);
}
api_delete_settings_params(array('category = ? AND access_url = ? AND subkey = ? ' =>
array('Plugins', $access_url_id, $plugin_name)));
$pluginpath = api_get_path(SYS_PLUGIN_PATH).$plugin_name.'/uninstall.php';
if (is_file($pluginpath) && is_readable($pluginpath)) {
//execute the uninstall procedure
require $pluginpath;
}
}
function get_areas_by_plugin($plugin_name) {
$result = api_get_settings('Plugins');
$areas = array();
foreach ($result as $row) {
if ($plugin_name == $row['selected_value']) {
$areas[] = $row['variable'];
}
}
return $areas;
}
function is_valid_plugin_location($location) {
return in_array($location, $this->plugin_list);
}
function is_valid_plugin($plugin_name) {
if (is_dir(api_get_path(SYS_PLUGIN_PATH).$plugin_name)) {
if (is_file(api_get_path(SYS_PLUGIN_PATH).$plugin_name.'/index.php')) {
return true;
}
}
return false;
}
….
89. Part B / 1 Plugin.lib.php
…...
function load_region($region, $main_template, $forced = false) {
if ($region == 'course_tool_plugin') {
return null;
}
ob_start();
$this->get_all_plugin_contents_by_region($region, $main_template, $forced);
$content = ob_get_contents();
ob_end_clean();
return $content;
}
/**
* Loads the translation files inside a plugin if exists. It loads by default english see the hello world plugin
*
* @todo add caching
* @param string $plugin_name
*/
function load_plugin_lang_variables($plugin_name) {
global $language_interface;
$root = api_get_path(SYS_PLUGIN_PATH);
//1. Loading english if exists
$english_path = $root.$plugin_name."/lang/english.php";
….
90. Part B / 1 Plugin.lib.php
…...
*/
function get_all_plugin_contents_by_region($region, $template, $forced = false) {
global $_plugins;
if (isset($_plugins[$region]) && is_array($_plugins[$region])) {
//if (1) {
//Load the plugin information
foreach ($_plugins[$region] as $plugin_name) {
//The plugin_info variable is available inside the plugin index
$plugin_info = $this->get_plugin_info($plugin_name, $forced);
//We also know where the plugin is
$plugin_info['current_region'] = $region;
// Loading the plugin/XXX/index.php file
$plugin_file = api_get_path(SYS_PLUGIN_PATH)."$plugin_name/index.php";
….
91. Part B / 1 Plugin.lib.php
…...
/**
* Loads plugin info
* @staticvar array $plugin_data
* @param string plugin name
* @param bool load from DB or from the static array
* @todo filter setting_form
* @return array
*/
function get_plugin_info($plugin_name, $forced = false) {
static $plugin_data = array();
if (isset($plugin_data[$plugin_name]) && $forced == false) {
return $plugin_data[$plugin_name];
} else {
$plugin_file = api_get_path(SYS_PLUGIN_PATH)."$plugin_name/plugin.php";
$plugin_info = array();
if (file_exists($plugin_file)) {
require $plugin_file;
}
//extra options
$plugin_settings = api_get_settings_params(array("subkey = ? AND category = ? AND type = ? " =>
array($plugin_name, 'Plugins','setting')));
$settings_filtered = array();
foreach ($plugin_settings as $item) {
$settings_filtered[$item['variable']] = $item['selected_value'];
}
$plugin_info['settings'] = $settings_filtered;
$plugin_data[$plugin_name] = $plugin_info;
return $plugin_info;
}
….
}
92. Part B / 1 Plugin.lib.php
…...
/*
* Get the template list
*/
function get_templates_list($plugin_name) {
$plugin_info = $this->get_plugin_info($plugin_name);
if (isset($plugin_info) && isset($plugin_info['templates'])) {
return $plugin_info['templates'];
} else {
return false;
}
}
….
/*
* Add a plugin to a region
*/
function add_to_region($plugin, $region) {
$access_url_id = api_get_current_access_url_id();
api_add_setting($plugin, $region, $plugin, 'region', 'Plugins', $plugin, null, null, null, $access_url_id, 1);
}
function install_course_plugins($course_id) {
$plugin_list = $this->get_installed_plugins();
…...
if (!empty($plugin_list)) {
foreach ($plugin_list as $plugin_name) {
$plugin_path = api_get_path(SYS_PLUGIN_PATH).$plugin_name.'/plugin.php';
if (file_exists($plugin_path)) {
require_once $plugin_path;
if (isset($plugin_info) && isset($plugin_info['plugin_class'])) {
$plugin_info['plugin_class']::create()->course_install($course_id);
}
}
}
}
93. Part B / 1 Plugin.lib.php
…...
function add_course_settings_form($form)
…....
function set_course_settings_defaults(& $values) {
…..
function save_course_settings($values) {
…...
/**
* Gets a nice array of keys for just the plugin's course settings
* @param string The plugin ID
* @return array Nice array of keys for course settings
*/
public function get_plugin_course_settings($plugin_name) {
…...
94. Part B / 1
General Plugin Pattern-Model
Development Pattern
➔
95. Part B / 1
Foundamental Files
Plugin.php
Index.php
Readme.txt
96. Part B / 1
Optional Files
Uninstall.php
Template.tpl
*.css and other
resources
97. Part B / 1
Plugin Develop Pattern
Create the foundamental and optional files
Put this files in a directory named
“MyPluginName”
Copy this directory in chamilo plugin
directory
Activate plugin in Plugin List Panel as
Admin
98. Part B / 2
Simple Plugin Creation Example
➔
Teacher List Plugin
112. Conclusion / Pattern Model
Create a plugin is very simple
There are necessary steps and
optional steps
Plugin creation is now a question of
planning what to do and knowing
chamilo functions and DB
113. Conclusion / Improvements
Create a Plugin Management System
Improve php files
Complete Uninstall.php role
Give more simple Api Package
plugin-oriented