parent
8e8c7997b4
commit
a95136fe5e
@ -0,0 +1,29 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
/** |
||||
* Class HookCreateUser |
||||
* @var \SplObjectStorage $observers |
||||
*/ |
||||
class HookCreateUser extends HookEvent implements HookCreateUserEventInterface |
||||
{ |
||||
protected function __construct() |
||||
{ |
||||
parent::__construct('HookCreateUser'); |
||||
} |
||||
|
||||
/** |
||||
* Update all the observers |
||||
* @param int $type |
||||
* @return int |
||||
*/ |
||||
public function notifyCreateUser($type) |
||||
{ |
||||
/** @var \HookCreateUserObserverInterface $observer */ |
||||
$this->eventData['type'] = $type; |
||||
foreach ($this->observers as $observer) { |
||||
$observer->hookCreateUser($this); |
||||
} |
||||
return 1; |
||||
} |
||||
} |
@ -0,0 +1,190 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
|
||||
abstract class HookEvent implements HookEventInterface |
||||
{ |
||||
public $observers; |
||||
public $eventName; |
||||
public $eventData; |
||||
|
||||
/** |
||||
* Construct Method |
||||
* @param $eventName |
||||
* @throws Exception |
||||
*/ |
||||
protected function __construct($eventName) |
||||
{ |
||||
if ($this->isHookPluginActive()) { |
||||
$this->observers = new SplObjectStorage(); |
||||
$this->eventName = $eventName; |
||||
$this->eventData = array(); |
||||
$this->plugin = HookManagementPlugin::create(); |
||||
$this->loadAttachments(); |
||||
} else { |
||||
throw new \Exception('Hook Management Plugin is not active'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Return the singleton instance of Hook event. |
||||
* If Hook Management plugin is not enabled, will return NULL |
||||
* @return HookEventInterface|null |
||||
*/ |
||||
public static function create() |
||||
{ |
||||
static $result = null; |
||||
|
||||
if ($result) { |
||||
return $result; |
||||
} else { |
||||
try { |
||||
$class = get_called_class(); |
||||
return new $class; |
||||
} catch (Exception $e) { |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* (PHP 5 >= 5.1.0)<br/> |
||||
* Attach an SplObserver |
||||
* @link http://php.net/manual/en/splsubject.attach.php |
||||
* @param SplObserver $observer <p> |
||||
* The <b>SplObserver</b> to attach. |
||||
* </p> |
||||
* @return void |
||||
*/ |
||||
public function attach(SplObserver $observer) |
||||
{ |
||||
global $_hook; |
||||
$observerClass = get_class($observer); |
||||
$_hook[$this->eventName][$observerClass] = 1; |
||||
$this->observers->attach($observer); |
||||
$this->plugin->insertHook($this->eventName, $observerClass, HOOK_TYPE_ALL); |
||||
} |
||||
|
||||
/** |
||||
* (PHP 5 >= 5.1.0)<br/> |
||||
* Detach an observer |
||||
* @link http://php.net/manual/en/splsubject.detach.php |
||||
* @param SplObserver $observer <p> |
||||
* The <b>SplObserver</b> to detach. |
||||
* </p> |
||||
* @return void |
||||
*/ |
||||
public function detach(SplObserver $observer) |
||||
{ |
||||
global $_hook; |
||||
$observerClass = get_class($observer); |
||||
unset($_hook[$this->eventName][$observerClass]); |
||||
$this->observers->detach($observer); |
||||
$this->plugin->deleteHook($this->eventName, $observerClass, HOOK_TYPE_ALL); |
||||
} |
||||
|
||||
/** |
||||
* (PHP 5 >= 5.1.0)<br/> |
||||
* Notify an observer |
||||
* @link http://php.net/manual/en/splsubject.notify.php |
||||
* @return void |
||||
*/ |
||||
public function notify() |
||||
{ |
||||
foreach ($this->observers as $observer) { |
||||
$observer->update($this); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Return the event name refer to where hook is used |
||||
* @return string |
||||
*/ |
||||
public function getEventName() |
||||
{ |
||||
return $this->eventName; |
||||
} |
||||
|
||||
/** |
||||
* Return an array containing all data needed by the hook observer to update |
||||
* @return array |
||||
*/ |
||||
public function getEventData() |
||||
{ |
||||
return $this->eventData; |
||||
} |
||||
|
||||
/** |
||||
* Set an array with data needed by hooks |
||||
* @param array $data |
||||
* @return $this |
||||
*/ |
||||
public function setEventData(array $data) |
||||
{ |
||||
$this->eventData = $data; |
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Load all hook observer already registered from Session or Database |
||||
* @return $this |
||||
*/ |
||||
public function loadAttachments() |
||||
{ |
||||
global $_hook; |
||||
if (isset($_hook[$this->eventName]) && is_array($_hook[$this->eventName])) { |
||||
foreach ($_hook[$this->eventName] as $hookObserver => $val) { |
||||
$hookObserverInstance = $hookObserver::create(); |
||||
$this->observers->attach($hookObserverInstance); |
||||
} |
||||
} else { |
||||
// Load from Database and save into global name |
||||
$_hook[$this->eventName] = $this->plugin->listHookObservers($this->eventName); |
||||
if (isset($_hook[$this->eventName]) && is_array($_hook[$this->eventName])) { |
||||
foreach ($_hook[$this->eventName] as $hookObserver => $val) { |
||||
$hookObserverInstance = $hookObserver::create(); |
||||
$this->observers->attach($hookObserverInstance); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Detach all hook observers |
||||
* @return $this |
||||
*/ |
||||
public function detachAll() |
||||
{ |
||||
global $_hook; |
||||
$_hook[$this->eventName] = null; |
||||
$this->observers->removeAll($this->observers); |
||||
} |
||||
|
||||
/** |
||||
* Clear all hookObservers without detach them |
||||
* @return mixed |
||||
*/ |
||||
public function clearAttachments() |
||||
{ |
||||
$this->observers->removeAll($this->observers); |
||||
} |
||||
|
||||
/** |
||||
* Return true if HookManagement plugin is active. Else, false. |
||||
* This is needed to check if hook event can be instantiated |
||||
* @return boolean |
||||
*/ |
||||
public static function isHookPluginActive() |
||||
{ |
||||
$isActive = false; |
||||
$appPlugin = new AppPlugin(); |
||||
$pluginList = $appPlugin->getInstalledPluginListName(); |
||||
var_dump($pluginList); |
||||
if (in_array(HOOK_MANAGEMENT_PLUGIN, $pluginList)) { |
||||
$isActive = true; |
||||
} |
||||
|
||||
return $isActive; |
||||
} |
||||
} |
@ -0,0 +1,206 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
/** |
||||
* Interface HookEventInterface |
||||
*/ |
||||
interface HookEventInterface extends SplSubject |
||||
{ |
||||
/** |
||||
* Return the singleton instance of Hook event. |
||||
* If Hook Management plugin is not enabled, will return NULL |
||||
* @return HookEventInterface|null |
||||
*/ |
||||
public static function create(); |
||||
|
||||
|
||||
/** |
||||
* Return an array containing all data needed by the hook observer to update |
||||
* @return array |
||||
*/ |
||||
public function getEventData(); |
||||
|
||||
/** |
||||
* Set an array with data needed by hooks |
||||
* @param array $data |
||||
* @return $this |
||||
*/ |
||||
public function setEventData(array $data); |
||||
|
||||
/** |
||||
* Return the event name refer to where hook is used |
||||
* @return string |
||||
*/ |
||||
public function getEventName(); |
||||
|
||||
|
||||
/** |
||||
* Clear all hookObservers without detach them |
||||
* @return mixed |
||||
*/ |
||||
public function clearAttachments(); |
||||
|
||||
|
||||
/** |
||||
* Load all hook observer already registered from Session or Database |
||||
* @return $this |
||||
*/ |
||||
public function loadAttachments(); |
||||
|
||||
/** |
||||
* Detach all hook observers |
||||
* @return $this |
||||
*/ |
||||
public function detachAll(); |
||||
|
||||
/** |
||||
* Return true if HookManagement plugin is active. Else, false. |
||||
* This is needed to store attachments into Database inside Hook plugin tables |
||||
* @return boolean |
||||
*/ |
||||
public static function isHookPluginActive(); |
||||
} |
||||
|
||||
interface HookObserverInterface extends SplObserver |
||||
{ |
||||
|
||||
} |
||||
|
||||
interface HookManagementInterface |
||||
{ |
||||
|
||||
/** |
||||
* Initialize Database storing hooks (events, observers, calls) |
||||
* This should be called right after installDatabase method |
||||
* @return int |
||||
*/ |
||||
public function initDatabase(); |
||||
|
||||
/** |
||||
* Insert hook into Database. Return insert id |
||||
* @param string $eventName |
||||
* @param string $observerClassName |
||||
* @param int $type |
||||
* @return int |
||||
*/ |
||||
public function insertHook($eventName, $observerClassName, $type); |
||||
|
||||
/** |
||||
* Delete hook from Database. Return deleted rows number |
||||
* @param string $eventName |
||||
* @param string $observerClassName |
||||
* @param int $type |
||||
* @return int |
||||
*/ |
||||
public function deleteHook($eventName, $observerClassName, $type); |
||||
|
||||
/** |
||||
* Update hook observer order by hook event |
||||
* @param $eventName |
||||
* @param $type |
||||
* @param $newOrder |
||||
* @return int |
||||
*/ |
||||
public function orderHook($eventName, $type, $newOrder); |
||||
|
||||
/** |
||||
* Return a list an associative array where keys are the hook observer class name |
||||
* @param $eventName |
||||
* @return array |
||||
*/ |
||||
public function listHookObservers($eventName); |
||||
|
||||
|
||||
/** |
||||
* Check if hooks (event, observer, call) exist in Database, if not, |
||||
* Will insert them into their respective table |
||||
* @param string $eventName |
||||
* @param string $observerClassName |
||||
* @return int |
||||
*/ |
||||
public function insertHookIfNotExist($eventName = null, $observerClassName = null); |
||||
|
||||
|
||||
/** |
||||
* Return the hook call id identified by hook event, hook observer and type |
||||
* @param $eventName |
||||
* @param $observerClassName |
||||
* @param $type |
||||
* @return mixed |
||||
*/ |
||||
public function getHookCallId($eventName, $observerClassName, $type); |
||||
} |
||||
|
||||
/** |
||||
* Interface HookCreateUserEventInterface |
||||
*/ |
||||
interface HookCreateUserEventInterface extends HookEventInterface |
||||
{ |
||||
/** |
||||
* Update all the observers |
||||
* @param int $type |
||||
* @return int |
||||
*/ |
||||
public function notifyCreateUser($type); |
||||
} |
||||
|
||||
/** |
||||
* Interface CreateUserHookInterface |
||||
*/ |
||||
interface HookCreateUserObserverInterface extends HookObserverInterface |
||||
{ |
||||
/** |
||||
* @param HookCreateUserEventInterface $hook |
||||
* @return int |
||||
*/ |
||||
public function hookCreateUser(HookCreateUserEventInterface $hook); |
||||
} |
||||
|
||||
/** |
||||
* Interface HookUpdateUserEventInterface |
||||
*/ |
||||
interface HookUpdateUserEventInterface extends HookEventInterface |
||||
{ |
||||
/** |
||||
* Update all the observers |
||||
* @param int $type |
||||
* @return int |
||||
*/ |
||||
public function notifyUpdateUser($type); |
||||
} |
||||
|
||||
/** |
||||
* Interface UpdateUserHookInterface |
||||
*/ |
||||
interface HookUpdateUserObserverInterface extends HookObserverInterface |
||||
{ |
||||
/** |
||||
* @param HookUpdateUserEventInterface $hook |
||||
* @return int |
||||
*/ |
||||
public function hookUpdateUser(HookUpdateUserEventInterface $hook); |
||||
} |
||||
|
||||
/** |
||||
* Interface HookAdminBlockEventInterface |
||||
*/ |
||||
interface HookAdminBlockEventInterface extends HookEventInterface |
||||
{ |
||||
/** |
||||
* @param int $type |
||||
* @return int |
||||
*/ |
||||
public function notifyAdminBlock($type); |
||||
} |
||||
|
||||
/** |
||||
* Interface HookAdminBlockObserverInterface |
||||
*/ |
||||
interface HookAdminBlockObserverInterface extends HookObserverInterface |
||||
{ |
||||
/** |
||||
* @param HookAdminBlockEventInterface $hook |
||||
* @return int |
||||
*/ |
||||
public function hookAdminBlock(HookAdminBlockEventInterface $hook); |
||||
} |
@ -0,0 +1,21 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
|
||||
class HookObserver implements HookObserverInterface |
||||
{ |
||||
|
||||
/** |
||||
* (PHP 5 >= 5.1.0)<br/> |
||||
* Receive update from subject |
||||
* @link http://php.net/manual/en/splobserver.update.php |
||||
* @param SplSubject $subject <p> |
||||
* The <b>SplSubject</b> notifying the observer of an update. |
||||
* </p> |
||||
* @return void |
||||
*/ |
||||
public function update(SplSubject $subject) |
||||
{ |
||||
// TODO: Implement update() method. |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
/** |
||||
* Class HookUpdateUser |
||||
* @var \SplObjectStorage $observers |
||||
*/ |
||||
class HookUpdateUser extends HookEvent implements HookUpdateUserEventInterface |
||||
{ |
||||
public function __construct() |
||||
{ |
||||
parent::__construct('HookUpdateUser'); |
||||
} |
||||
|
||||
/** |
||||
* Update all the observers |
||||
* @param int $type |
||||
* @return int |
||||
*/ |
||||
public function notifyUpdateUser($type) |
||||
{ |
||||
/** @var \HookUpdateUserObserverInterface $observer */ |
||||
$this->eventData['type'] = $type; |
||||
foreach ($this->observers as $observer) { |
||||
$observer->hookUpdateUser($this); |
||||
} |
||||
return 1; |
||||
} |
||||
} |
@ -0,0 +1,62 @@ |
||||
Hook Management plugin for Chamilo LMS |
||||
======================================= |
||||
Enable hooks in Chamilo to allow plugin to extend functionality. |
||||
|
||||
Hooks structure is based on Observer pattern |
||||
|
||||
The base structure is composed by 3 Interfaces |
||||
* HookEvent: This will call the hook methods in Chamilo code |
||||
* HookObserver: This will be executed when a Hook event is called |
||||
* HookManagement: Manage hooks, creation, instantiation, persistence, connection to database and is implemented to a Plugin |
||||
|
||||
|
||||
|
||||
On this version exists Hooks for: |
||||
|
||||
|
||||
|Number| Directory | EventClass | ObserverInterface | Reference | |
||||
|------|-----------------------------------|----------------|---------------------------------|---------------------------| |
||||
| 1| /main/inc/lib/usermanager.lib.php | HookCreateUser | HookCreateUserObserverInterface | Usermanager::createUser() | |
||||
| 2| /main/inc/lib/usermanager.lib.php | HookUpdateUser | HookUpdateUserObserverInterface | Usermanager::updateUser() | |
||||
| 3| /main/admin/index.php | HookAdminBlock | HookAdminBlockObserverInterface | ADMIN BLOCK | |
||||
|
||||
# What I need to use Hook? |
||||
|
||||
You need to create a class extending `HookObserver` class |
||||
and implementing any (or many) Hook Observer Interfaces, e.g. `HookCreateUserObserverInterface`. |
||||
An observer can implement many Hook observer interface. |
||||
This was done to allow Plugin to have a unique Hook Observer class |
||||
Dont forget to add your Hook Observer class to autoload file |
||||
|
||||
# How to add MyHookObserver to my plugin? |
||||
|
||||
Before this, the hook management plugin must be enabled |
||||
|
||||
When installing your plugin (or other functions) you should call |
||||
the attach method from an specific Hook Observer class, e.g. `HookCreateUser` class |
||||
``` |
||||
$myHookObserver = MyHookObserver::create(); |
||||
HookCreateUser::create()->attach($myHookObserver); |
||||
``` |
||||
|
||||
# How to remove MyHookObserver to my plugin? |
||||
|
||||
For remove the HookObserver, this should be detached from specific Hook Event class |
||||
``` |
||||
$myHookObserver = MyHookObserver::create(); |
||||
HookCreateUser::create()->detach($myHookObserver); |
||||
``` |
||||
|
||||
# How to add HookEvents to Chamilo? |
||||
|
||||
To expand Hook in Chamilo you should do: |
||||
1. Identify an event could be customized by a plugin |
||||
2. Create an interface for the Hook Event and and Hook Observer. |
||||
The names should be like the Hooks interfaces already created, |
||||
with The Pattern: HookXyzEventInterface and HookXyzObserverInterface, |
||||
e.g. Hook event: `HookUpdateUserEventInterface`, Hook observer: `HookUpdateUserObserverInterface` |
||||
3. Add at least a notify method to Hook Event Interface and update method to Hook Observer Interface |
||||
4. Create a class extending `HookEvent` class and implementing your Hook Event Interface |
||||
5. Complete the notify method calling to Hook observer update |
||||
6. Add your Interfaces and Class to autoload file |
||||
7. Test your hook. if your Observer require data, you can use the data property from Hook Event |
@ -0,0 +1,14 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
/** |
||||
* Config the plugin |
||||
* @author Daniel Alejandro Barreto Alva <daniel.barreto@beeznest.com> |
||||
* @package chamilo.plugin.hookmanagement |
||||
*/ |
||||
|
||||
define('TABLE_PLUGIN_HOOK_OBSERVER', 'plugin_hook_observer'); |
||||
define('TABLE_PLUGIN_HOOK_CALL', 'plugin_hook_call'); |
||||
define('TABLE_PLUGIN_HOOK_EVENT', 'plugin_hook_event'); |
||||
require_once __DIR__ . '/../../main/inc/global.inc.php'; |
||||
require_once api_get_path(LIBRARY_PATH) . 'plugin.class.php'; |
||||
require_once api_get_path(PLUGIN_PATH) . 'hookmanagement/src/HookManagementPlugin.class.php'; |
@ -0,0 +1,7 @@ |
||||
<?php |
||||
/** |
||||
* Created by PhpStorm. |
||||
* User: dbarreto |
||||
* Date: 15/12/14 |
||||
* Time: 09:27 AM |
||||
*/ |
@ -0,0 +1,2 @@ |
||||
<?php |
||||
/* For license terms, see /license.txt */ |
@ -0,0 +1,17 @@ |
||||
<?php |
||||
/* For license terms, see /license.txt */ |
||||
/** |
||||
* This script is included by main/admin/settings.lib.php and generally |
||||
* includes things to execute in the main database (settings_current table) |
||||
* @package chamilo.plugin.hookmanagement |
||||
*/ |
||||
|
||||
/** |
||||
* Initialization |
||||
*/ |
||||
|
||||
require_once dirname(__FILE__) . '/config.php'; |
||||
if (!api_is_platform_admin()) { |
||||
die ('You must have admin permissions to install plugins'); |
||||
} |
||||
HookManagementPlugin::create()->install(); |
@ -0,0 +1,8 @@ |
||||
<?php |
||||
|
||||
/* Strings for settings */ |
||||
$strings['plugin_title'] = 'Hook Management'; |
||||
$strings['plugin_comment'] = 'This plugin allow the use of hooks for others plugins, To use hooks, this plugins must be enabled'; |
||||
$strings['tool_enable'] = 'Enable Hook management plugin'; |
||||
$strings['tool_enable_help'] = "Escoja si desea activar el gestor de Hooks."; |
||||
|
@ -0,0 +1,7 @@ |
||||
<?php |
||||
|
||||
/* Strings for settings */ |
||||
$strings['plugin_title'] = 'Gestor de Hooks'; |
||||
$strings['plugin_comment'] = 'Este plugin permite el uso de hooks y los gestiona. Debe estar activado para usar los hooks'; |
||||
$strings['tool_enable'] = 'Activar plugin Gestor de Hooks'; |
||||
$strings['tool_enable_help'] = "Escoja si desea activar el gestor de Hooks."; |
@ -0,0 +1 @@ |
||||
This plugin, as the rest of Chamilo, is released under the GNU/GPLv3 license. |
@ -0,0 +1,12 @@ |
||||
<?php |
||||
/* For license terms, see /license.txt */ |
||||
/** |
||||
* This script is a configuration file for the date plugin. You can use it as a master for other platform plugins (course plugins are slightly different). |
||||
* These settings will be used in the administration interface for plugins (Chamilo configuration settings->Plugins) |
||||
* @package chamilo.plugin.hookmanagement |
||||
*/ |
||||
/** |
||||
* Plugin details (must be present) |
||||
*/ |
||||
require_once __DIR__ . '/config.php'; |
||||
$plugin_info = HookManagementPlugin::create()->get_info(); |
@ -0,0 +1,99 @@ |
||||
Hook Management plugin<br/><br/> |
||||
|
||||
<article class="markdown-body entry-content" itemprop="mainContentOfPage"><h1> |
||||
<a id="user-content-hook-management-plugin-for-chamilo-lms" class="anchor" href="#hook-management-plugin-for-chamilo-lms" aria-hidden="true"><span class="octicon octicon-link"></span></a>Hook Management plugin for Chamilo LMS</h1> |
||||
|
||||
<p>Enable hooks in Chamilo to allow plugin to extend functionality.</p> |
||||
|
||||
<p>Hooks structure is based on Observer pattern</p> |
||||
|
||||
<p>The base structure is composed by 3 Interfaces</p> |
||||
|
||||
<ul class="task-list"> |
||||
<li>HookEvent: This will call the hook methods in Chamilo code</li> |
||||
<li>HookObserver: This will be executed when a Hook event is called</li> |
||||
<li>HookManagement: Manage hooks, creation, instantiation, persistence, connection to database and is implemented to a Plugin</li> |
||||
</ul> |
||||
|
||||
<p>On this version exists Hooks for:</p> |
||||
|
||||
<table> |
||||
<thead> |
||||
<tr> |
||||
<th>Number</th> |
||||
<th>Directory</th> |
||||
<th>EventClass</th> |
||||
<th>ObserverInterface</th> |
||||
<th>Reference</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<tr> |
||||
<td>1</td> |
||||
<td>/main/inc/lib/usermanager.lib.php</td> |
||||
<td>HookCreateUser</td> |
||||
<td>HookCreateUserObserverInterface</td> |
||||
<td>Usermanager::createUser()</td> |
||||
</tr> |
||||
<tr> |
||||
<td>2</td> |
||||
<td>/main/inc/lib/usermanager.lib.php</td> |
||||
<td>HookUpdateUser</td> |
||||
<td>HookUpdateUserObserverInterface</td> |
||||
<td>Usermanager::updateUser()</td> |
||||
</tr> |
||||
<tr> |
||||
<td>3</td> |
||||
<td>/main/admin/index.php</td> |
||||
<td>HookAdminBlock</td> |
||||
<td>HookAdminBlockObserverInterface</td> |
||||
<td>ADMIN BLOCK</td> |
||||
</tr> |
||||
</tbody> |
||||
</table> |
||||
|
||||
<h1> |
||||
<a id="user-content-what-i-need-to-use-hook" class="anchor" href="#what-i-need-to-use-hook" aria-hidden="true"><span class="octicon octicon-link"></span></a>What I need to use Hook?</h1> |
||||
|
||||
<p>You need to create a class extending <code>HookObserver</code> class |
||||
and implementing any (or many) Hook Observer Interfaces, e.g. <code>HookCreateUserObserverInterface</code>. |
||||
An observer can implement many Hook observer interface. |
||||
This was done to allow Plugin to have a unique Hook Observer class |
||||
Dont forget to add your Hook Observer class to autoload file</p> |
||||
|
||||
<h1> |
||||
<a id="user-content-how-to-add-myhookobserver-to-my-plugin" class="anchor" href="#how-to-add-myhookobserver-to-my-plugin" aria-hidden="true"><span class="octicon octicon-link"></span></a>How to add MyHookObserver to my plugin?</h1> |
||||
|
||||
<p>Before this, the hook management plugin must be enabled</p> |
||||
|
||||
<p>When installing your plugin (or other functions) you should call |
||||
the attach method from an specific Hook Observer class, e.g. <code>HookCreateUser</code> class</p> |
||||
|
||||
<pre><code>$myHookObserver = MyHookObserver::create(); |
||||
HookCreateUser::create()->attach($myHookObserver); |
||||
</code></pre> |
||||
|
||||
<h1> |
||||
<a id="user-content-how-to-remove-myhookobserver-to-my-plugin" class="anchor" href="#how-to-remove-myhookobserver-to-my-plugin" aria-hidden="true"><span class="octicon octicon-link"></span></a>How to remove MyHookObserver to my plugin?</h1> |
||||
|
||||
<p>For remove the HookObserver, this should be detached from specific Hook Event class</p> |
||||
|
||||
<pre><code>$myHookObserver = MyHookObserver::create(); |
||||
HookCreateUser::create()->detach($myHookObserver); |
||||
</code></pre> |
||||
|
||||
<h1> |
||||
<a id="user-content-how-to-add-hookevents-to-chamilo" class="anchor" href="#how-to-add-hookevents-to-chamilo" aria-hidden="true"><span class="octicon octicon-link"></span></a>How to add HookEvents to Chamilo?</h1> |
||||
|
||||
<p>To expand Hook in Chamilo you should do: |
||||
1. Identify an event could be customized by a plugin |
||||
2. Create an interface for the Hook Event and and Hook Observer. |
||||
The names should be like the Hooks interfaces already created, |
||||
with The Pattern: HookXyzEventInterface and HookXyzObserverInterface, |
||||
e.g. Hook event: <code>HookUpdateUserEventInterface</code>, Hook observer: <code>HookUpdateUserObserverInterface</code> |
||||
3. Add at least a notify method to Hook Event Interface and update method to Hook Observer Interface |
||||
4. Create a class extending <code>HookEvent</code> class and implementing your Hook Event Interface |
||||
5. Complete the notify method calling to Hook observer update |
||||
6. Add your Interfaces and Class to autoload file |
||||
7. Test your hook. if your Observer require data, you can use the data property from Hook Event</p> |
||||
</article> |
@ -0,0 +1,458 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
/** |
||||
* @TODO: Improve description |
||||
* @package chamilo.plugin.hookmanagement |
||||
*/ |
||||
|
||||
class HookManagementPlugin extends Plugin implements HookManagementInterface |
||||
{ |
||||
/** |
||||
* Constructor |
||||
*/ |
||||
function __construct() |
||||
{ |
||||
$parameters = array( |
||||
'tool_enable' => 'boolean', |
||||
); |
||||
|
||||
$this->tables[TABLE_PLUGIN_HOOK_OBSERVER] = Database::get_main_table(TABLE_PLUGIN_HOOK_OBSERVER); |
||||
$this->tables[TABLE_PLUGIN_HOOK_EVENT] = Database::get_main_table(TABLE_PLUGIN_HOOK_EVENT); |
||||
$this->tables[TABLE_PLUGIN_HOOK_CALL] = Database::get_main_table(TABLE_PLUGIN_HOOK_CALL); |
||||
|
||||
$this->hookCalls = array(); |
||||
$this->hookEvents = array(); |
||||
$this->hookObservers = array(); |
||||
|
||||
parent::__construct('1.0', 'Daniel Barreto', $parameters); |
||||
} |
||||
|
||||
/** |
||||
* Instance the plugin |
||||
* @staticvar null $result |
||||
* @return HookManagementPlugin |
||||
*/ |
||||
static function create() |
||||
{ |
||||
static $result = null; |
||||
|
||||
return $result ? $result : $result = new self(); |
||||
} |
||||
|
||||
/** |
||||
* Install the plugin |
||||
* @return void |
||||
*/ |
||||
public function install() |
||||
{ |
||||
$this->installDatabase(); |
||||
$this->initDatabase(); |
||||
} |
||||
|
||||
/** |
||||
* Uninstall the plugin |
||||
* @return void |
||||
*/ |
||||
public function uninstall() |
||||
{ |
||||
$this->uninstallDatabase(); |
||||
} |
||||
|
||||
/** |
||||
* Create the database tables for the plugin |
||||
* @return void |
||||
*/ |
||||
private function installDatabase() |
||||
{ |
||||
$sql = 'CREATE TABLE IF NOT EXISTS ' . $this->tables[TABLE_PLUGIN_HOOK_OBSERVER] . '( ' . |
||||
'id int UNSIGNED NOT NULL AUTO_INCREMENT, ' . |
||||
'class_name varchar(255) UNIQUE, ' . |
||||
'plugin_name varchar(255) NULL, ' . |
||||
'PRIMARY KEY PK_hook_management_hook_observer (id) ' . |
||||
'); '; |
||||
Database::query($sql); |
||||
|
||||
$sql = 'CREATE TABLE IF NOT EXISTS ' . $this->tables[TABLE_PLUGIN_HOOK_EVENT] . '( ' . |
||||
'id int UNSIGNED NOT NULL AUTO_INCREMENT, ' . |
||||
'class_name varchar(255) UNIQUE, ' . |
||||
'description varchar(255), ' . |
||||
'PRIMARY KEY PK_hook_management_hook_event (id) ' . |
||||
'); '; |
||||
Database::query($sql); |
||||
|
||||
$sql = 'CREATE TABLE IF NOT EXISTS ' . $this->tables[TABLE_PLUGIN_HOOK_CALL] . '( ' . |
||||
'id int UNSIGNED NOT NULL AUTO_INCREMENT, ' . |
||||
'hook_event_id int UNSIGNED NOT NULL, ' . |
||||
'hook_observer_id int UNSIGNED NOT NULL, ' . |
||||
'type tinyint NOT NULL, ' . |
||||
'hook_order int UNSIGNED NOT NULL, ' . |
||||
'enabled tinyint NOT NULL, ' . |
||||
'PRIMARY KEY PK_hook_management_hook_call (id) ' . |
||||
'); '; |
||||
Database::query($sql); |
||||
} |
||||
|
||||
/** |
||||
* Initialize Database storing hooks (events, observers, calls) |
||||
* This should be called right after installDatabase method |
||||
* @return int |
||||
*/ |
||||
public function initDatabase() |
||||
{ |
||||
// Search hook events |
||||
$hookEvents = array(); |
||||
foreach (get_declared_classes() as $class) { |
||||
if (is_subclass_of($class, '\HookEvent')) { |
||||
$interfaces = class_implements($class); |
||||
$hookInterfaces = array(); |
||||
foreach ($interfaces as $interface) { |
||||
$hookInterface = (preg_filter('/Hook(.+)EventInterface/', '$1', $interface)); |
||||
if (!empty($hookInterface)) { |
||||
$hookInterfaces[] = $hookInterface; |
||||
} |
||||
} |
||||
$hookEvents[$class] = $hookInterfaces; |
||||
} |
||||
} |
||||
// Search hook observers |
||||
$hookObservers = array(); |
||||
foreach (get_declared_classes() as $class) { |
||||
if (is_subclass_of($class, '\HookObserver')) { |
||||
$interfaces = class_implements($class); |
||||
$hookInterfaces = array(); |
||||
foreach ($interfaces as $interface) { |
||||
$hookInterface = (preg_filter('/Hook(.+)ObserverInterface/', '$1', $interface)); |
||||
if (!empty($hookInterface)) { |
||||
$hookInterfaces[] =$hookInterface; |
||||
} |
||||
} |
||||
$hookObservers[$class] = $hookInterfaces; |
||||
} |
||||
} |
||||
// Search hook calls |
||||
$hookCalls = array(); |
||||
foreach ($hookEvents as $hookEvent => $eventInterfaces) { |
||||
if (!empty($eventInterfaces)) { |
||||
$order = 0; |
||||
foreach ($hookObservers as $hookObserver => $observerInterfaces) { |
||||
if ($observerInterfaces === $eventInterfaces) { |
||||
$order += 1; |
||||
$hookCalls[] = array($hookEvent, $hookObserver, HOOK_TYPE_PRE, $order); |
||||
$hookCalls[] = array($hookEvent, $hookObserver, HOOK_TYPE_POST, $order); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Insert hook events |
||||
foreach ($hookEvents as $hookEvent => $v) { |
||||
$attributes = array( |
||||
'class_name' => $hookEvent, |
||||
'description' => get_plugin_lang('HookDescription' . $hookEvent, 'HookManagementPlugin'), |
||||
); |
||||
$id = Database::insert($this->tables[TABLE_PLUGIN_HOOK_EVENT], $attributes); |
||||
// store hook event into property |
||||
$this->hookEvents[$hookEvent] = $id; |
||||
} |
||||
|
||||
// Insert hook observer |
||||
foreach ($hookObservers as $hookObserver => $v) { |
||||
$attributes = array( |
||||
'class_name' => $hookObserver, |
||||
); |
||||
$id = Database::insert($this->tables[TABLE_PLUGIN_HOOK_OBSERVER], $attributes); |
||||
// store hook observer into property |
||||
$this->hookObservers[$hookObserver] = $id; |
||||
} |
||||
|
||||
// Insert hook call |
||||
foreach ($hookCalls as $hookCall) { |
||||
$attributes = array( |
||||
'hook_event_id' => $this->hookEvents[$hookCall[0]], |
||||
'hook_observer_id' => $this->hookObservers[$hookCall[1]], |
||||
'type' => $hookCall[2], |
||||
'hook_order' => $hookCall[3], |
||||
); |
||||
// store hook call into property |
||||
$id = Database::insert($this->tables[TABLE_PLUGIN_HOOK_CALL], $attributes); |
||||
$this->hookCalls[$hookCall[0]][$hookCall[1]][$hookCall[2]] = $id; |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
/** |
||||
* Drop the database tables for the plugin |
||||
* @return void |
||||
*/ |
||||
private function uninstallDatabase() |
||||
{ |
||||
$sql = 'DROP TABLE IF EXISTS ' . $this->tables[TABLE_PLUGIN_HOOK_CALL] . '; '; |
||||
Database::query($sql); |
||||
$sql = 'DROP TABLE IF EXISTS ' . $this->tables[TABLE_PLUGIN_HOOK_EVENT] . '; '; |
||||
Database::query($sql); |
||||
$sql = 'DROP TABLE IF EXISTS ' . $this->tables[TABLE_PLUGIN_HOOK_OBSERVER] . '; '; |
||||
Database::query($sql); |
||||
} |
||||
|
||||
/** |
||||
* Insert hook into Database. Return insert id |
||||
* @param string $eventName |
||||
* @param string $observerClassName |
||||
* @param int $type |
||||
* @return int |
||||
*/ |
||||
public function insertHook($eventName, $observerClassName, $type) |
||||
{ |
||||
if ($type === HOOK_TYPE_ALL) { |
||||
$this->insertHook($eventName, $observerClassName, HOOK_TYPE_PRE); |
||||
$this->insertHook($eventName, $observerClassName, HOOK_TYPE_POST); |
||||
} else { |
||||
$this->insertHookIfNotExist($eventName, $observerClassName); |
||||
// Check if exists hook call |
||||
$row = Database::select('id, enabled', |
||||
$this->tables[TABLE_PLUGIN_HOOK_CALL], |
||||
array( |
||||
'where' => array( |
||||
'hook_event_id = ? ' => $this->hookEvents[$eventName], |
||||
'AND hook_observer_id = ? ' => $this->hookObservers[$observerClassName], |
||||
'AND type = ? ' => $type, |
||||
), |
||||
), |
||||
'ASSOC'); |
||||
|
||||
if (!empty($row) && is_array($row)) { |
||||
// Check if is hook call is active |
||||
if ((int) $row['enabled'] === 0) { |
||||
Database::update( |
||||
$this->tables[TABLE_PLUGIN_HOOK_CALL], |
||||
array( |
||||
'enabled' => 1, |
||||
), |
||||
array( |
||||
'id = ?' => $row['id'], |
||||
) |
||||
); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Delete hook from Database. Return deleted rows number |
||||
* @param string $eventName |
||||
* @param string $observerClassName |
||||
* @param int $type |
||||
* @return int |
||||
*/ |
||||
public function deleteHook($eventName, $observerClassName, $type) |
||||
{ |
||||
if ($type === HOOK_TYPE_ALL) { |
||||
$this->insertHook($eventName, $observerClassName, HOOK_TYPE_PRE); |
||||
$this->insertHook($eventName, $observerClassName, HOOK_TYPE_POST); |
||||
} else { |
||||
$this->insertHookIfNotExist($eventName, $observerClassName); |
||||
|
||||
Database::update( |
||||
$this->tables[TABLE_PLUGIN_HOOK_CALL], |
||||
array( |
||||
'enabled' => 0, |
||||
), |
||||
array( |
||||
'id = ? ' => $this->hookCalls[$eventName][$observerClassName][$type], |
||||
) |
||||
); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Update hook observer order by hook event |
||||
* @param $eventName |
||||
* @param $type |
||||
* @param $hookOrders |
||||
* @return int |
||||
*/ |
||||
public function orderHook($eventName, $type, $hookOrders) |
||||
{ |
||||
foreach ($this->hookCalls[$eventName] as $observerClassName => $types) { |
||||
foreach ($hookOrders as $oldOrder => $newOrder) |
||||
{ |
||||
$res = Database::update( |
||||
$this->tables[TABLE_PLUGIN_HOOK_CALL], |
||||
array( |
||||
'hook_order ' => $newOrder, |
||||
), |
||||
array( |
||||
'id = ? ' => $types[$type], |
||||
'AND hook_order = ? ' => $oldOrder, |
||||
) |
||||
); |
||||
|
||||
if ($res) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Return a list an associative array where keys are the active hook observer class name |
||||
* @param $eventName |
||||
* @return array |
||||
*/ |
||||
public function listHookObservers($eventName) |
||||
{ |
||||
$array = array(); |
||||
$joinTable = $this->tables[TABLE_PLUGIN_HOOK_CALL] . 'hc ' . |
||||
' INNER JOIN ' . $this->tables[TABLE_PLUGIN_HOOK_EVENT] . 'he ' . |
||||
' ON hc.hook_event_id = he.id ' . |
||||
' INNER JOIN ' . $this->tables[TABLE_PLUGIN_HOOK_OBSERVER] . ' ho ' . |
||||
' ON hc.hook_observer_id = ho.id '; |
||||
$columns = 'ho.class_name, hc.enabled'; |
||||
$where = array('where' => array('he.class_name = ? ' => $eventName, 'AND hc.enabled = ? ' => 1)); |
||||
$rows = Database::select($columns, $joinTable, $where); |
||||
|
||||
foreach ($rows as $row) { |
||||
$array[$row['class_name']] = $row['enabled']; |
||||
} |
||||
|
||||
return $array; |
||||
} |
||||
|
||||
/** |
||||
* Check if hooks (event, observer, call) exist in Database, if not, |
||||
* Will insert them into their respective table |
||||
* @param string $eventName |
||||
* @param string $observerClassName |
||||
* @return int |
||||
*/ |
||||
public function insertHookIfNotExist($eventName = null, $observerClassName = null) |
||||
{ |
||||
// Check if exists hook event |
||||
if (isset($eventName) && !isset($this->hookEvents[$eventName])) { |
||||
$attributes = array( |
||||
'class_name' => $eventName, |
||||
'description' => get_plugin_lang('HookDescription' . $eventName, 'HookManagementPlugin'), |
||||
); |
||||
$id = Database::insert($this->tables[TABLE_PLUGIN_HOOK_EVENT], $attributes); |
||||
$this->hookEvents[$eventName] = $id; |
||||
} |
||||
|
||||
// Check if exists hook observer |
||||
if (isset($observerClassName) && !isset($this->hookObservers[$observerClassName])){ |
||||
$attributes = array( |
||||
'class_name' => $observerClassName, |
||||
); |
||||
$id = Database::insert($this->tables[TABLE_PLUGIN_HOOK_OBSERVER], $attributes); |
||||
$this->hookObservers[$observerClassName] = $id; |
||||
} |
||||
|
||||
if ( |
||||
isset($eventName) && |
||||
isset($observerClassName) && |
||||
!isset($this->hookCalls[$eventName][$observerClassName]) |
||||
) { |
||||
// HOOK TYPE PRE |
||||
|
||||
$row = Database::select( |
||||
'MAX(hook_order) as hook_order', |
||||
$this->tables[TABLE_PLUGIN_HOOK_CALL], |
||||
array( |
||||
'where' => array( |
||||
'hook_event_id = ? ' =>$this->hookEvents[$eventName], |
||||
'AND type = ? ' => HOOK_TYPE_PRE, |
||||
), |
||||
), |
||||
'ASSOC' |
||||
); |
||||
|
||||
// Check if exists hook call |
||||
$id = Database::insert( |
||||
$this->tables[TABLE_PLUGIN_HOOK_CALL], |
||||
array( |
||||
'hook_event_id' => $this->hookEvents[$eventName], |
||||
'hook_observer_id' => $this->hookObservers[$observerClassName], |
||||
'type' => HOOK_TYPE_PRE, |
||||
'enabled' => 0, |
||||
'hook_order' => $row['hook_order'] + 1, |
||||
) |
||||
); |
||||
|
||||
$this->hookCalls[$eventName][$observerClassName][HOOK_TYPE_PRE] = $id; |
||||
|
||||
// HOOK TYPE POST |
||||
|
||||
$row = Database::select( |
||||
'MAX(hook_order) as hook_order', |
||||
$this->tables[TABLE_PLUGIN_HOOK_CALL], |
||||
array( |
||||
'where' => array( |
||||
'hook_event_id = ? ' =>$this->hookEvents[$eventName], |
||||
'AND type = ? ' => HOOK_TYPE_POST, |
||||
), |
||||
), |
||||
'ASSOC' |
||||
); |
||||
|
||||
// Check if exists hook call |
||||
$id = Database::insert( |
||||
$this->tables[TABLE_PLUGIN_HOOK_CALL], |
||||
array( |
||||
'hook_event_id' => $this->hookEvents[$eventName], |
||||
'hook_observer_id' => $this->hookObservers[$observerClassName], |
||||
'type' => HOOK_TYPE_POST, |
||||
'enabled' => 0, |
||||
'hook_order' => $row['hook_order'] + 1, |
||||
) |
||||
); |
||||
|
||||
$this->hookCalls[$eventName][$observerClassName][HOOK_TYPE_POST] = $id; |
||||
|
||||
} elseif (isset($eventName) && !isset($observerClassName)) { |
||||
foreach ($this->hookObservers as $observer => $id) { |
||||
$this->insertHookIfNotExist($eventName, $observer); |
||||
} |
||||
} elseif (!isset($eventName) && isset($observerClassName)) { |
||||
foreach ($this->hookEvents as $event => $id) { |
||||
$this->insertHookIfNotExist($event, $observerClassName); |
||||
} |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
/** |
||||
* Return the hook call id identified by hook event, hook observer and type |
||||
* @param $eventName |
||||
* @param $observerClassName |
||||
* @param $type |
||||
* @return mixed |
||||
*/ |
||||
public function getHookCallId($eventName, $observerClassName, $type) |
||||
{ |
||||
$eventName = Database::escape_string($eventName); |
||||
$observerClassName($observerClassName); |
||||
$type = Database::escape_string($type); |
||||
$joinTable = $this->tables[TABLE_PLUGIN_HOOK_CALL] . 'hc ' . |
||||
' INNER JOIN ' . $this->tables[TABLE_PLUGIN_HOOK_EVENT] . 'he ' . |
||||
' ON hc.hook_event_id = he.id ' . |
||||
' INNER JOIN ' . $this->tables[TABLE_PLUGIN_HOOK_OBSERVER] . ' ho ' . |
||||
' ON hc.hook_observer_id = ho.id '; |
||||
$row = Database::select( |
||||
'id', |
||||
$joinTable, |
||||
array( |
||||
'where' => array( |
||||
'he.class_name = ? ' => $eventName, |
||||
'AND ho.class_name = ? ' => $observerClassName, |
||||
'AND hc.type = ? ' => $type, |
||||
), |
||||
), |
||||
'ASSOC' |
||||
); |
||||
|
||||
return $row['id']; |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
<?php |
||||
/* For license terms, see /license.txt */ |
||||
/** |
||||
* This script is included by main/admin/settings.lib.php when unselecting a plugin |
||||
* and is meant to remove things installed by the install.php script in both |
||||
* the global database and the courses tables |
||||
* @package chamilo.plugin.hookmanagement |
||||
*/ |
||||
|
||||
/** |
||||
* Queries |
||||
*/ |
||||
require_once dirname(__FILE__) . '/config.php'; |
||||
if (!api_is_platform_admin()) { |
||||
die ('You must have admin permissions to uninstall plugins'); |
||||
} |
||||
HookManagementPlugin::create()->uninstall(); |
Loading…
Reference in new issue