diff --git a/mod/admin.php b/mod/admin.php index 39a28158c..e3b537fcf 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -214,11 +214,12 @@ function admin_content(App $a) $r = q("SELECT `name` FROM `addon` WHERE `plugin_admin` = 1 ORDER BY `name`"); $aside_tools['addons_admin'] = []; + $addons_admin = []; foreach ($r as $h) { $addon = $h['name']; $aside_tools['addons_admin'][] = ["admin/addons/" . $addon, $addon, "addon"]; // temp addons with admin - $a->addons_admin[] = $addon; + $addons_admin[] = $addon; } $t = get_markup_template('admin/aside.tpl'); @@ -243,7 +244,7 @@ function admin_content(App $a) $o = admin_page_users($a); break; case 'addons': - $o = admin_page_addons($a); + $o = admin_page_addons($a, $addons_admin); break; case 'themes': $o = admin_page_themes($a); @@ -932,7 +933,7 @@ function admin_page_summary(App $a) '$platform' => FRIENDICA_PLATFORM, '$codename' => FRIENDICA_CODENAME, '$build' => Config::get('system', 'build'), - '$addons' => [L10n::t('Active addons'), $a->addons], + '$addons' => [L10n::t('Active addons'), Addon::getEnabledList()], '$serversettings' => $server_settings, '$showwarning' => $showwarning, '$warningtext' => $warningtext @@ -1956,10 +1957,11 @@ function admin_page_users(App $a) * * The returned string returned hulds the HTML code of the page. * - * @param App $a + * @param App $a + * @param array $addons_admin A list of admin addon names * @return string */ -function admin_page_addons(App $a) +function admin_page_addons(App $a, array $addons_admin) { /* * Single addon @@ -1971,27 +1973,25 @@ function admin_page_addons(App $a) return ''; } - if (x($_GET, "a") && $_GET['a'] == "t") { + if (defaults($_GET, 'a', '') == "t") { BaseModule::checkFormSecurityTokenRedirectOnError('/admin/addons', 'admin_themes', 't'); // Toggle addon status - $idx = array_search($addon, $a->addons); - if ($idx !== false) { - unset($a->addons[$idx]); + if (Addon::isEnabled($addon)) { Addon::uninstall($addon); info(L10n::t("Addon %s disabled.", $addon)); } else { - $a->addons[] = $addon; Addon::install($addon); info(L10n::t("Addon %s enabled.", $addon)); } - Config::set("system", "addon", implode(", ", $a->addons)); + + Addon::saveEnabledList(); $a->internalRedirect('admin/addons'); return ''; // NOTREACHED } // display addon details - if (in_array($addon, $a->addons)) { + if (Addon::isEnabled($addon)) { $status = "on"; $action = L10n::t("Disable"); } else { @@ -2007,7 +2007,7 @@ function admin_page_addons(App $a) } $admin_form = ""; - if (in_array($addon, $a->addons_admin)) { + if (in_array($addon, $addons_admin)) { require_once "addon/$addon/$addon.php"; $func = $addon . '_addon_admin'; $func($a, $admin_form); @@ -2058,7 +2058,7 @@ function admin_page_addons(App $a) $show_addon = true; // If the addon is unsupported, then only show it, when it is enabled - if ((strtolower($info["status"]) == "unsupported") && !in_array($id, $a->addons)) { + if ((strtolower($info["status"]) == "unsupported") && !Addon::isEnabled($id)) { $show_addon = false; } @@ -2068,7 +2068,7 @@ function admin_page_addons(App $a) } if ($show_addon) { - $addons[] = [$id, (in_array($id, $a->addons) ? "on" : "off"), $info]; + $addons[] = [$id, (Addon::isEnabled($id) ? "on" : "off"), $info]; } } } diff --git a/mod/friendica.php b/mod/friendica.php index f2cb5c50b..bf3f7942f 100644 --- a/mod/friendica.php +++ b/mod/friendica.php @@ -31,15 +31,7 @@ function friendica_init(App $a) $admin = false; } - $visible_addons = []; - if (is_array($a->addons) && count($a->addons)) { - $r = q("SELECT * FROM `addon` WHERE `hidden` = 0"); - if (DBA::isResult($r)) { - foreach ($r as $rr) { - $visible_addons[] = $rr['name']; - } - } - } + $visible_addons = Addon::getVisibleList(); Config::load('feature_lock'); $locked_features = []; @@ -91,16 +83,7 @@ function friendica_content(App $a) $o .= L10n::t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'); $o .= '
' . PHP_EOL; - $visible_addons = []; - if (is_array($a->addons) && count($a->addons)) { - $r = q("SELECT * FROM `addon` WHERE `hidden` = 0"); - if (DBA::isResult($r)) { - foreach ($r as $rr) { - $visible_addons[] = $rr['name']; - } - } - } - + $visible_addons = Addon::getVisibleList(); if (count($visible_addons)) { $o .= '' . L10n::t('Installed addons/apps:') . '
' . PHP_EOL; $sorted = $visible_addons; diff --git a/src/App.php b/src/App.php index e312d8721..d8d6439d7 100644 --- a/src/App.php +++ b/src/App.php @@ -50,11 +50,8 @@ class App public $argv; public $argc; public $module; - public $hooks = []; public $timezone; public $interactive = true; - public $addons; - public $addons_admin = []; public $identities; public $is_mobile = false; public $is_tablet = false; @@ -360,7 +357,7 @@ class App Core\Config::load(); if ($this->getMode()->has(App\Mode::DBAVAILABLE)) { - Core\Addon::loadHooks(); + Core\Hook::loadHooks(); $this->loadAddonConfig(); } diff --git a/src/Core/Addon.php b/src/Core/Addon.php index d2f89ce27..6b2d34170 100644 --- a/src/Core/Addon.php +++ b/src/Core/Addon.php @@ -16,7 +16,14 @@ require_once 'include/dba.php'; class Addon extends BaseObject { /** - * @brief Synchronise addons: + * List of the names of enabled addons + * + * @var array + */ + private static $addons = []; + + /** + * @brief Synchronize addons: * * system.addon contains a comma-separated list of names * of addons which are used on this system. @@ -27,15 +34,13 @@ class Addon extends BaseObject * call the install procedure and add it to the database. * */ - public static function check() + public static function loadAddons() { - $a = self::getApp(); + $installed_addons = []; $r = DBA::select('addon', [], ['installed' => 1]); if (DBA::isResult($r)) { - $installed = DBA::toArray($r); - } else { - $installed = []; + $installed_addons = DBA::toArray($r); } $addons = Config::get('system', 'addon'); @@ -45,31 +50,23 @@ class Addon extends BaseObject $addons_arr = explode(',', str_replace(' ', '', $addons)); } - $a->addons = $addons_arr; + self::$addons = $addons_arr; $installed_arr = []; - if (count($installed)) { - foreach ($installed as $i) { - if (!in_array($i['name'], $addons_arr)) { - self::uninstall($i['name']); - } else { - $installed_arr[] = $i['name']; - } + foreach ($installed_addons as $addon) { + if (!self::isEnabled($addon['name'])) { + self::uninstall($addon['name']); + } else { + $installed_arr[] = $addon['name']; } } - if (count($addons_arr)) { - foreach ($addons_arr as $p) { - if (!in_array($p, $installed_arr)) { - self::install($p); - } + foreach (self::$addons as $p) { + if (!in_array($p, $installed_arr)) { + self::install($p); } } - - self::loadHooks(); - - return; } /** @@ -88,6 +85,8 @@ class Addon extends BaseObject $func = $addon . '_uninstall'; $func(); } + + unset(self::$addons[$idx]); } /** @@ -110,10 +109,10 @@ class Addon extends BaseObject $func = $addon . '_install'; $func(); - $addon_admin = (function_exists($addon."_addon_admin") ? 1 : 0); + $addon_admin = (function_exists($addon . "_addon_admin") ? 1 : 0); DBA::insert('addon', ['name' => $addon, 'installed' => true, - 'timestamp' => $t, 'plugin_admin' => $addon_admin]); + 'timestamp' => $t, 'plugin_admin' => $addon_admin]); // we can add the following with the previous SQL // once most site tables have been updated. @@ -122,6 +121,10 @@ class Addon extends BaseObject if (file_exists('addon/' . $addon . '/.hidden')) { DBA::update('addon', ['hidden' => true], ['name' => $addon]); } + + if (!self::isEnabled($addon)) { + self::$addons[] = $addon; + } return true; } else { logger("Addons: FAILED installing " . $addon); @@ -174,165 +177,6 @@ class Addon extends BaseObject } } - /** - * @brief check if addon is enabled - * - * @param string $addon - * @return boolean - */ - public static function isEnabled($addon) - { - return DBA::exists('addon', ['installed' => true, 'name' => $addon]); - } - - - /** - * @brief registers a hook. - * - * @param string $hook the name of the hook - * @param string $file the name of the file that hooks into - * @param string $function the name of the function that the hook will call - * @param int $priority A priority (defaults to 0) - * @return mixed|bool - */ - public static function registerHook($hook, $file, $function, $priority = 0) - { - $file = str_replace(self::getApp()->getBasePath() . DIRECTORY_SEPARATOR, '', $file); - - $condition = ['hook' => $hook, 'file' => $file, 'function' => $function]; - $exists = DBA::exists('hook', $condition); - if ($exists) { - return true; - } - - $r = DBA::insert('hook', ['hook' => $hook, 'file' => $file, 'function' => $function, 'priority' => $priority]); - - return $r; - } - - /** - * @brief unregisters a hook. - * - * @param string $hook the name of the hook - * @param string $file the name of the file that hooks into - * @param string $function the name of the function that the hook called - * @return array - */ - public static function unregisterHook($hook, $file, $function) - { - $relative_file = str_replace(self::getApp()->getBasePath() . DIRECTORY_SEPARATOR, '', $file); - - // This here is only needed for fixing a problem that existed on the develop branch - $condition = ['hook' => $hook, 'file' => $file, 'function' => $function]; - DBA::delete('hook', $condition); - - $condition = ['hook' => $hook, 'file' => $relative_file, 'function' => $function]; - $r = DBA::delete('hook', $condition); - return $r; - } - - /** - * Load hooks - */ - public static function loadHooks() - { - $a = self::getApp(); - $a->hooks = []; - $r = DBA::select('hook', ['hook', 'file', 'function'], [], ['order' => ['priority' => 'desc', 'file']]); - - while ($rr = DBA::fetch($r)) { - if (! array_key_exists($rr['hook'], $a->hooks)) { - $a->hooks[$rr['hook']] = []; - } - $a->hooks[$rr['hook']][] = [$rr['file'],$rr['function']]; - } - DBA::close($r); - } - - /** - * @brief Forks a hook. - * - * Use this function when you want to fork a hook via the worker. - * - * @param string $name of the hook to call - * @param string|array $data to transmit to the callback handler - */ - public static function forkHooks($priority, $name, $data = null) - { - $a = self::getApp(); - - if (is_array($a->hooks) && array_key_exists($name, $a->hooks)) { - foreach ($a->hooks[$name] as $hook) { - Worker::add($priority, 'ForkHook', $name, $hook, $data); - } - } - } - - /** - * @brief Calls a hook. - * - * Use this function when you want to be able to allow a hook to manipulate - * the provided data. - * - * @param string $name of the hook to call - * @param string|array &$data to transmit to the callback handler - */ - public static function callHooks($name, &$data = null) - { - $a = self::getApp(); - - if (is_array($a->hooks) && array_key_exists($name, $a->hooks)) { - foreach ($a->hooks[$name] as $hook) { - self::callSingleHook($a, $name, $hook, $data); - } - } - } - - /** - * @brief Calls a single hook. - * - * @param App $a - * @param string $name of the hook to call - * @param array $hook Hook data - * @param string|array &$data to transmit to the callback handler - */ - public static function callSingleHook(App $a, $name, $hook, &$data = null) - { - // Don't run a theme's hook if the user isn't using the theme - if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/' . $a->getCurrentTheme()) === false) { - return; - } - - @include_once($hook[0]); - if (function_exists($hook[1])) { - $func = $hook[1]; - $func($a, $data); - } else { - // remove orphan hooks - $condition = ['hook' => $name, 'file' => $hook[0], 'function' => $hook[1]]; - DBA::delete('hook', $condition, ['cascade' => false]); - } - } - - /** - * check if an app_menu hook exist for addon $name. - * Return true if the addon is an app - */ - public static function isApp($name) - { - $a = self::getApp(); - - if (is_array($a->hooks) && (array_key_exists('app_menu', $a->hooks))) { - foreach ($a->hooks['app_menu'] as $hook) { - if ($hook[0] == 'addon/'.$name.'/'.$name.'.php') { - return true; - } - } - } - - return false; - } - /** * @brief Parse addon comment in search of addon infos. * @@ -401,4 +245,92 @@ class Addon extends BaseObject } return $info; } + + /** + * Checks if the provided addon is enabled + * + * @param string $addon + * @return boolean + */ + public static function isEnabled($addon) + { + return in_array($addon, self::$addons); + } + + public static function getEnabledList() + { + return self::$addons; + } + + /** + * Saves the current enabled addon list in the system.addon config key + * + * @return boolean + */ + public static function saveEnabledList() + { + return Config::set("system", "addon", implode(", ", self::$addons)); + } + + /** + * Returns the list of non-hidden enabled addon names + * + * @return array + */ + public static function getVisibleList() + { + $visible_addons = []; + $stmt = DBA::select('addon', ['name'], ['hidden' => false, 'installed' => true]); + if (DBA::isResult($stmt)) { + foreach (DBA::toArray($stmt) as $addon) { + $visible_addons[] = $addon['name']; + } + } + + return $visible_addons; + } + + /** + * Shim of Hook::register left for backward compatibility purpose. + * + * @see Hook::register + * @deprecated since version 2018.12 + * @param string $hook the name of the hook + * @param string $file the name of the file that hooks into + * @param string $function the name of the function that the hook will call + * @param int $priority A priority (defaults to 0) + * @return mixed|bool + */ + public static function registerHook($hook, $file, $function, $priority = 0) + { + return Hook::register($hook, $file, $function, $priority); + } + + /** + * Shim of Hook::unregister left for backward compatibility purpose. + * + * @see Hook::unregister + * @deprecated since version 2018.12 + * @param string $hook the name of the hook + * @param string $file the name of the file that hooks into + * @param string $function the name of the function that the hook called + * @return boolean + */ + public static function unregisterHook($hook, $file, $function) + { + return Hook::unregister($hook, $file, $function); + } + + /** + * Shim of Hook::callAll left for backward-compatibility purpose. + * + * @see Hook::callAll + * @deprecated since version 2018.12 + * @param string $name of the hook to call + * @param string|array &$data to transmit to the callback handler + */ + public static function callHooks($name, &$data = null) + { + Hook::callAll($name, $data); + } } diff --git a/src/Object/Post.php b/src/Object/Post.php index 70428ab84..85d7a3b8c 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -771,7 +771,7 @@ class Post extends BaseObject * Hmmm, code depending on the presence of a particular addon? * This should be better if done by a hook */ - if (in_array('qcomment', $a->addons)) { + if (Addon::isEnabled('qcomment')) { $qc = ((local_user()) ? PConfig::get(local_user(), 'qcomment', 'words') : null); $qcomment = (($qc) ? explode("\n", $qc) : null); } diff --git a/src/Worker/Cron.php b/src/Worker/Cron.php index b6dd896cd..54e6cb676 100644 --- a/src/Worker/Cron.php +++ b/src/Worker/Cron.php @@ -7,6 +7,7 @@ namespace Friendica\Worker; use Friendica\BaseObject; use Friendica\Core\Addon; use Friendica\Core\Config; +use Friendica\Core\Hook; use Friendica\Core\Protocol; use Friendica\Core\Worker; use Friendica\Database\DBA; @@ -45,7 +46,7 @@ class Cron logger('cron: start'); // Fork the cron jobs in separate parts to avoid problems when one of them is crashing - Addon::forkHooks($a->queue['priority'], "cron"); + Hook::fork($a->queue['priority'], "cron"); // run queue delivery process in the background Worker::add(PRIORITY_NEGLIGIBLE, "Queue"); diff --git a/src/Worker/Expire.php b/src/Worker/Expire.php index b6096b584..de2133bdc 100644 --- a/src/Worker/Expire.php +++ b/src/Worker/Expire.php @@ -7,8 +7,8 @@ namespace Friendica\Worker; use Friendica\BaseObject; -use Friendica\Core\Addon; use Friendica\Core\Config; +use Friendica\Core\Hook; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Item; @@ -17,13 +17,13 @@ require_once 'include/dba.php'; class Expire { - public static function execute($param = '', $hook_name = '') + public static function execute($param = '', $hook_function = '') { $a = BaseObject::getApp(); require_once 'include/items.php'; - Addon::loadHooks(); + Hook::loadHooks(); if ($param == 'delete') { logger('Delete expired items', LOGGER_DEBUG); @@ -62,11 +62,11 @@ class Expire logger('Expire items for user '.$user['uid'].' ('.$user['username'].') - done ', LOGGER_DEBUG); } return; - } elseif (!empty($hook_name) && ($param == 'hook') && is_array($a->hooks) && array_key_exists("expire", $a->hooks)) { - foreach ($a->hooks["expire"] as $hook) { - if ($hook[1] == $hook_name) { + } elseif ($param == 'hook' && !empty($hook_function)) { + foreach (Hook::getByName('expire') as $hook) { + if ($hook[1] == $hook_function) { logger("Calling expire hook '" . $hook[1] . "'", LOGGER_DEBUG); - Addon::callSingleHook($a, $hook_name, $hook, $data); + Hook::callSingle($a, 'expire', $hook, $data); } } return; @@ -86,13 +86,10 @@ class Expire DBA::close($r); logger('expire: calling hooks'); - - if (is_array($a->hooks) && array_key_exists('expire', $a->hooks)) { - foreach ($a->hooks['expire'] as $hook) { - logger("Calling expire hook for '" . $hook[1] . "'", LOGGER_DEBUG); - Worker::add(['priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true], - 'Expire', 'hook', $hook[1]); - } + foreach (Hook::getByName('expire') as $hook) { + logger("Calling expire hook for '" . $hook[1] . "'", LOGGER_DEBUG); + Worker::add(['priority' => $a->queue['priority'], 'created' => $a->queue['created'], 'dont_fork' => true], + 'Expire', 'hook', $hook[1]); } logger('expire: end'); diff --git a/src/Worker/ForkHook.php b/src/Worker/ForkHook.php index 3654bdd3c..586d1496e 100644 --- a/src/Worker/ForkHook.php +++ b/src/Worker/ForkHook.php @@ -5,7 +5,7 @@ namespace Friendica\Worker; -use Friendica\Core\Addon; +use Friendica\Core\Hook; Class ForkHook { @@ -13,6 +13,6 @@ Class ForkHook { $a = \Friendica\BaseObject::getApp(); - Addon::callSingleHook($a, $name, $hook, $data); + Hook::callSingle($a, $name, $hook, $data); } } diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index 3edc15c3b..31000a26f 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -7,10 +7,12 @@ namespace Friendica\Worker; use Friendica\BaseObject; use Friendica\Core\Addon; use Friendica\Core\Config; +use Friendica\Core\Hook; use Friendica\Core\Protocol; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Contact; +use Friendica\Model\Conversation; use Friendica\Model\Group; use Friendica\Model\Item; use Friendica\Model\PushSubscriber; @@ -20,7 +22,6 @@ use Friendica\Protocol\ActivityPub; use Friendica\Protocol\Diaspora; use Friendica\Protocol\OStatus; use Friendica\Protocol\Salmon; -use Friendica\Model\Conversation; require_once 'include/dba.php'; require_once 'include/items.php'; @@ -501,7 +502,7 @@ class Notifier logger('notifier: calling hooks for ' . $cmd . ' ' . $item_id, LOGGER_DEBUG); if ($normal_mode) { - Addon::forkHooks($a->queue['priority'], 'notifier_normal', $target_item); + Hook::fork($a->queue['priority'], 'notifier_normal', $target_item); } Addon::callHooks('notifier_end',$target_item);