Add Hook management plugin and base library - refs BT#9092

1.10.x
Daniel Barreto 10 years ago
parent 8e8c7997b4
commit a95136fe5e
  1. 29
      main/inc/lib/hook/HookCreateUser.class.php
  2. 190
      main/inc/lib/hook/HookEvent.class.php
  3. 206
      main/inc/lib/hook/HookInterfaces.php
  4. 21
      main/inc/lib/hook/HookObserver.class.php
  5. 29
      main/inc/lib/hook/HookUpdateUser.class.php
  6. 7
      main/inc/lib/main_api.lib.php
  7. 15
      main/inc/lib/usermanager.lib.php
  8. 62
      plugin/hookmanagement/README.md
  9. 14
      plugin/hookmanagement/config.php
  10. 7
      plugin/hookmanagement/hook/hookName_pre_test.hook.php
  11. 2
      plugin/hookmanagement/index.php
  12. 17
      plugin/hookmanagement/install.php
  13. 8
      plugin/hookmanagement/lang/english.php
  14. 7
      plugin/hookmanagement/lang/spanish.php
  15. 1
      plugin/hookmanagement/license.txt
  16. 12
      plugin/hookmanagement/plugin.php
  17. 99
      plugin/hookmanagement/readme.txt
  18. 458
      plugin/hookmanagement/src/HookManagementPlugin.class.php
  19. 17
      plugin/hookmanagement/uninstall.php

@ -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 &gt;= 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 &gt;= 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 &gt;= 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 &gt;= 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;
}
}

@ -355,6 +355,13 @@ define('CATALOG_COURSES', 0);
define('CATALOG_SESSIONS', 1);
define('CATALOG_COURSES_SESSIONS', 2);
//Hook
define('HOOK_TYPE_PRE', 0);
define('HOOK_TYPE_POST', 1);
define('HOOK_TYPE_ALL', 10);
define('HOOK_MANAGEMENT_PLUGIN', 'hookmanagement');
/**
* Inclusion of internationalization libraries
*/

@ -80,6 +80,10 @@ class UserManager
$encrypt_method = '',
$send_mail = false
) {
$hook = HookCreateUser::create();
if (!empty($hook)) {
$hook->notifyCreateUser(HOOK_TYPE_PRE);
}
global $_user, $_configuration;
$original_password = $password;
$access_url_id = 1;
@ -242,6 +246,9 @@ class UserManager
}
self::update_extra_field_value($return, 'already_logged_in', 'false');
if (!empty($hook)) {
$hook->notifyCreateUser(HOOK_TYPE_POST);
}
return $return;
}
@ -582,6 +589,10 @@ class UserManager
$send_email = false,
$reset_password = 0
) {
$hook = HookUpdateUser::create();
if (!empty($hook)) {
$hook->notifyUpdateUser(HOOK_TYPE_PRE);
}
global $_configuration;
$original_password = $password;
@ -690,6 +701,10 @@ class UserManager
@api_mail_html($recipient_name, $email, $emailsubject, $emailbody, $sender_name, $email_admin);
}
if (!empty($hook)) {
$hook->notifyUpdateUser(HOOK_TYPE_POST);
}
return $return;
}

@ -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()-&gt;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()-&gt;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…
Cancel
Save