.
* ---------------------------------------------------------------------
*/
/**
* Based on cacti plugin system
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
use Psr\SimpleCache\CacheInterface;
use Glpi\Marketplace\View as MarketplaceView;
use Glpi\Marketplace\Controller as MarketplaceController;
class Plugin extends CommonDBTM {
// Class constant : Plugin state
/**
* @var int Unknown plugin state
*/
const UNKNOWN = -1;
/**
* @var int Plugin was discovered but not installed
*
* @note Plugins are never actually set to this status?
*/
const ANEW = 0;
/**
* @var int Plugin is installed and enabled
*/
const ACTIVATED = 1;
/**
* @var int Plugin is not installed
*/
const NOTINSTALLED = 2;
/**
* @var int Plugin is installed but needs configured before it can be enabled
*/
const TOBECONFIGURED = 3;
/**
* @var int Plugin is installed but not enabled
*/
const NOTACTIVATED = 4;
/**
* @var int Plugin was previously discovered, but the plugin directory is missing now. The DB needs cleaned.
*/
const TOBECLEANED = 5;
/**
* @var int The plugin's files are for a newer version than installed. An update is needed.
*/
const NOTUPDATED = 6;
static $rightname = 'config';
/**
* Plugin init state.
*
* @var boolean
*/
private static $plugins_init = false;
/**
* Activated plugin list
*
* @var string[]
*/
private static $activated_plugins = [];
/**
* Loaded plugin list
*
* @var string[]
*/
private static $loaded_plugins = [];
static function getTypeName($nb = 0) {
return _n('Plugin', 'Plugins', $nb);
}
static function getMenuName() {
return static::getTypeName(Session::getPluralNumber());
}
static function getMenuContent() {
$menu = parent::getMenuContent() ?: [];
if (static::canView()) {
$redirect_mp = MarketplaceController::getPluginPageConfig();
$menu['title'] = self::getMenuName();
$menu['page'] = $redirect_mp == MarketplaceController::MP_REPLACE_YES
? '/front/marketplace.php'
: '/front/plugin.php';
$menu['icon'] = self::getIcon();
}
if (count($menu)) {
return $menu;
}
return false;
}
static function getAdditionalMenuLinks() {
if (!static::canView()) {
return false;
}
$mp_icon = MarketplaceView::getIcon();
$mp_title = MarketplaceView::getTypeName();
$marketplace = "$mp_title";
$cl_icon = Plugin::getIcon();
$cl_title = Plugin::getTypeName();
$classic = "$cl_title";
return [
$marketplace => MarketplaceView::getSearchURL(false),
$classic => Plugin::getSearchURL(false),
];
}
static function getAdditionalMenuOptions() {
if (static::canView()) {
return [
'marketplace' => [
'icon' => MarketplaceView::geticon(),
'title' => MarketplaceView::getTypeName(),
'page' => MarketplaceView::getSearchURL(false),
]
];
}
}
/**
* Retrieve an item from the database using its directory
*
* @param string $dir directory of the plugin
*
* @return boolean
**/
function getFromDBbyDir($dir) {
return $this->getFromDBByCrit([$this->getTable() . '.directory' => $dir]);
}
/**
* Init plugins list.
*
* @param boolean $load_plugins Whether to load active/configurable plugins or not.
* @param array $excluded_plugins List of plugins to exclude
*
* @return void
**/
function init(bool $load_plugins = false, array $excluded_plugins = []) {
global $DB;
self::$plugins_init = false;
self::$activated_plugins = [];
self::$loaded_plugins = [];
if (!isset($DB) || !$DB->connected) {
// Cannot init plugins list if DB is not connected
self::$plugins_init = true;
return;
}
$this->checkStates(false, $excluded_plugins);
$plugins = $this->find(['state' => [self::ACTIVATED, self::TOBECONFIGURED]]);
self::$plugins_init = true;
if ($load_plugins && count($plugins)) {
foreach ($plugins as $plugin) {
if (in_array($plugin['directory'], $excluded_plugins)) {
continue;
}
if (!$this->isLoadable($plugin['directory'])) {
continue;
}
Plugin::load($plugin['directory']);
if ((int)$plugin['state'] === self::ACTIVATED) {
self::$activated_plugins[] = $plugin['directory'];
}
}
// For plugins which require action after all plugin init
Plugin::doHook("post_init");
}
}
/**
* Init a plugin including setup.php file
* launching plugin_init_NAME function after checking compatibility
*
* @param string $plugin_key System name (Plugin directory)
* @param boolean $withhook Load hook functions (false by default)
*
* @return void
**/
static function load($plugin_key, $withhook = false) {
global $LOADED_PLUGINS;
$loaded = false;
foreach (PLUGINS_DIRECTORIES as $base_dir) {
if (!is_dir($base_dir)) {
continue;
}
if (file_exists("$base_dir/$plugin_key/setup.php")) {
$loaded = true;
$plugin_directory = "$base_dir/$plugin_key";
include_once("$plugin_directory/setup.php");
if (!in_array($plugin_key, self::$loaded_plugins)) {
self::$loaded_plugins[] = $plugin_key;
$init_function = "plugin_init_$plugin_key";
if (function_exists($init_function)) {
$init_function();
$LOADED_PLUGINS[$plugin_key] = $plugin_directory;
self::loadLang($plugin_key);
}
}
}
if ($withhook) {
self::includeHook($plugin_key);
}
if ($loaded) {
break;
}
}
}
/**
* Unload a plugin.
*
* @param string $plugin_key System name (Plugin directory)
*
* @return void
*/
private function unload($plugin_key) {
global $LOADED_PLUGINS;
if (($key = array_search($plugin_key, self::$activated_plugins)) !== false) {
unset(self::$activated_plugins[$key]);
}
if (($key = array_search($plugin_key, self::$loaded_plugins)) !== false) {
unset(self::$loaded_plugins[$key]);
}
if (isset($LOADED_PLUGINS[$plugin_key])) {
unset($LOADED_PLUGINS[$plugin_key]);
}
}
/**
* Load lang file for a plugin
*
* @param string $plugin_key System name (Plugin directory)
* @param string $forcelang Force a specific lang (default '')
* @param string $coretrytoload Lang trying to be loaded from core (default '')
*
* @return void
**/
static function loadLang($plugin_key, $forcelang = '', $coretrytoload = '') {
global $CFG_GLPI, $TRANSLATE;
// For compatibility for plugins using $LANG
$trytoload = 'en_GB';
if (isset($_SESSION['glpilanguage'])) {
$trytoload = $_SESSION["glpilanguage"];
}
// Force to load a specific lang
if (!empty($forcelang)) {
$trytoload = $forcelang;
}
// If not set try default lang file
if (empty($trytoload)) {
$trytoload = $CFG_GLPI["language"];
}
if (empty($coretrytoload)) {
$coretrytoload = $trytoload;
}
// New localisation system
$mofile = false;
foreach (PLUGINS_DIRECTORIES as $base_dir) {
if (!is_dir($base_dir)) {
continue;
}
$locales_dir = "$base_dir/$plugin_key/locales/";
if (file_exists($locales_dir.$CFG_GLPI["languages"][$trytoload][1])) {
$mofile = $locales_dir.$CFG_GLPI["languages"][$trytoload][1];
} else if (!empty($CFG_GLPI["language"])
&& file_exists($locales_dir.$CFG_GLPI["languages"][$CFG_GLPI["language"]][1])) {
$mofile = $locales_dir.$CFG_GLPI["languages"][$CFG_GLPI["language"]][1];
} else if (file_exists($locales_dir."en_GB.mo")) {
$mofile = $locales_dir."en_GB.mo";
}
if ($mofile !== false) {
break;
}
}
if ($mofile !== false) {
$TRANSLATE->addTranslationFile(
'gettext',
$mofile,
$plugin_key,
$coretrytoload
);
}
$mofile = str_replace($locales_dir, GLPI_LOCAL_I18N_DIR . '/'.$plugin_key . '/', $mofile);
$phpfile = str_replace('.mo', '.php', $mofile);
// Load local PHP file if it exists
if (file_exists($phpfile)) {
$TRANSLATE->addTranslationFile('phparray', $phpfile, $plugin_key, $coretrytoload);
}
// Load local MO file if it exists -- keep last so it gets precedence
if (file_exists($mofile)) {
$TRANSLATE->addTranslationFile('gettext', $mofile, $plugin_key, $coretrytoload);
}
}
/**
* Check plugins states and detect new plugins.
*
* @param boolean $scan_inactive_and_new_plugins
* @param array $excluded_plugins List of plugins to exclude
*
* @return void
*/
public function checkStates($scan_inactive_and_new_plugins = false, array $excluded_plugins = []) {
$directories = [];
// Add known plugins to the check list
$condition = $scan_inactive_and_new_plugins ? [] : ['state' => self::ACTIVATED];
$known_plugins = $this->find($condition);
foreach ($known_plugins as $plugin) {
$directories[] = $plugin['directory'];
}
if ($scan_inactive_and_new_plugins) {
// Add found directories to the check list
foreach (PLUGINS_DIRECTORIES as $plugins_directory) {
if (!is_dir($plugins_directory)) {
continue;
}
$directory_handle = opendir($plugins_directory);
while (false !== ($filename = readdir($directory_handle))) {
if (!in_array($filename, ['.svn', '.', '..'])
&& is_dir($plugins_directory . DIRECTORY_SEPARATOR . $filename)) {
$directories[] = $filename;
}
}
}
}
// Prevent duplicated checks
$directories = array_unique($directories);
// Check all directories from the checklist
foreach ($directories as $directory) {
if (in_array($directory, $excluded_plugins)) {
continue;
}
$this->checkPluginState($directory);
}
}
/**
* Check plugin state.
*
* @param string $plugin_key System name (Plugin directory)
*
* return void
*/
public function checkPluginState($plugin_key) {
$plugin = new self();
$is_already_known = $plugin->getFromDBByCrit(['directory' => $plugin_key]);
$informations = $this->getInformationsFromDirectory($plugin_key);
if (empty($informations)) {
if (!$is_already_known) {
// Plugin is not known and we are unable to load informations, we ignore it
return;
}
// Try to get information from a plugin that lists current name as its old name
// If something found, and not already registerd in DB,, base plugin informations on it
// If nothing found, mark plugin as "To be cleaned"
$new_specs = $this->getNewInfoAndDirBasedOnOldName($plugin_key);
if (null !== $new_specs
&& countElementsInTable(self::getTable(), ['directory' => $new_specs['directory']]) === 0) {
$plugin_key = $new_specs['directory'];
$informations = $new_specs['informations'];
} else {
trigger_error(
sprintf(
'Unable to load plugin "%s" informations.',
$plugin_key
),
E_USER_WARNING
);
// Plugin is known but we are unable to load informations, we ignore it
return;
}
}
if (!$is_already_known && array_key_exists('oldname', $informations)) {
// Plugin not known but was named differently before, we try to load state using old name
$is_already_known = $plugin->getFromDBByCrit(['directory' => $informations['oldname']]);
}
if (!$is_already_known) {
// Plugin not known, add it in DB
$this->add(
array_merge(
$informations,
[
'state' => self::NOTINSTALLED,
'directory' => $plugin_key,
]
)
);
return;
}
if ($informations['version'] != $plugin->fields['version']
|| $plugin_key != $plugin->fields['directory']) {
// Plugin known version differs from informations or plugin has been renamed,
// update informations in database
$input = $informations;
$input['id'] = $plugin->fields['id'];
$input['directory'] = $plugin_key;
if (!in_array($plugin->fields['state'], [self::ANEW, self::NOTINSTALLED, self::NOTUPDATED])) {
// mark it as 'updatable' unless it was not installed
trigger_error(
sprintf(
'Plugin "%s" version changed. It has been deactivated as its update process has to be launched.',
$plugin_key
),
E_USER_WARNING
);
$input['state'] = self::NOTUPDATED;
}
$this->update($input);
$this->unload($plugin_key);
// reset menu
if (isset($_SESSION['glpimenu'])) {
unset($_SESSION['glpimenu']);
}
return;
}
// Check if configuration state changed
if (in_array((int)$plugin->fields['state'], [self::ACTIVATED, self::TOBECONFIGURED, self::NOTACTIVATED], true)) {
$function = 'plugin_' . $plugin_key . '_check_config';
$is_config_ok = !function_exists($function) || $function();
if ((int)$plugin->fields['state'] === self::TOBECONFIGURED && $is_config_ok) {
// Remove TOBECONFIGURED state if configuration is OK now
$this->update(
[
'id' => $plugin->fields['id'],
'state' => self::NOTACTIVATED
]
);
return;
} else if ((int)$plugin->fields['state'] !== self::TOBECONFIGURED && !$is_config_ok) {
// Add TOBECONFIGURED state if configuration is required
trigger_error(
sprintf(
'Plugin "%s" must be configured.',
$plugin_key
),
E_USER_WARNING
);
$this->update(
[
'id' => $plugin->fields['id'],
'state' => self::TOBECONFIGURED
]
);
return;
}
}
if (self::ACTIVATED !== (int)$plugin->fields['state']) {
// Plugin is not activated, nothing to do
return;
}
// Check that active state of plugin can be kept
$usage_ok = true;
// Check compatibility
ob_start();
if (!$this->checkVersions($plugin_key)) {
$usage_ok = false;
}
ob_end_clean();
// Check prerequisites
if ($usage_ok) {
$function = 'plugin_' . $plugin_key . '_check_prerequisites';
if (function_exists($function)) {
ob_start();
if (!$function()) {
$usage_ok = false;
}
ob_end_clean();
}
}
if (!$usage_ok) {
// Deactivate if not usable
trigger_error(
sprintf(
'Plugin "%s" prerequisites are not matched. It has been deactivated.',
$plugin_key
),
E_USER_WARNING
);
$this->unactivate($plugin->fields['id']);
}
}
/**
* Get plugin information based on its old name.
*
* @param string $oldname
*
* @return null|array If a new directory is found, returns an array containing 'directory' and 'informations' keys.
*/
private function getNewInfoAndDirBasedOnOldName($oldname) {
$plugins_directories = new DirectoryIterator(GLPI_ROOT . '/plugins');
/** @var SplFileInfo $plugin_directory */
foreach ($plugins_directories as $plugin_directory) {
if (in_array($plugin_directory->getFilename(), ['.svn', '.', '..'])
|| !is_dir($plugin_directory->getRealPath())) {
continue;
}
$informations = $this->getInformationsFromDirectory($plugin_directory->getFilename());
if (array_key_exists('oldname', $informations) && $informations['oldname'] === $oldname) {
// Return informations if oldname specified in parsed directory matches passed value
return [
'directory' => $plugin_directory->getFilename(),
'informations' => $informations,
];
}
}
return null;
}
/**
* Get list of all plugins
*
* @param array $fields Fields to retrieve
* @param array $order Query ORDER clause
*
* @return array
*/
public function getList(array $fields = [], array $order = ['name', 'directory']) {
global $DB;
$query = [
'FROM' => $this->getTable()
];
if (count($fields) > 0) {
$query['FIELDS'] = $fields;
}
if (count($order) > 0) {
$query['ORDER'] = $order;
}
$iterator = $DB->request($query);
return iterator_to_array($iterator, false);
}
/**
* Uninstall a plugin
*
* @param integer $ID ID of the plugin (The `id` field, not directory)
**/
function uninstall($ID) {
$message = '';
$type = ERROR;
if ($this->getFromDB($ID)) {
CronTask::Unregister($this->fields['directory']);
self::load($this->fields['directory'], true); // Force load in case plugin is not active
FieldUnicity::deleteForItemtype($this->fields['directory']);
Link_Itemtype::deleteForItemtype($this->fields['directory']);
// Run the Plugin's Uninstall Function first
$function = 'plugin_' . $this->fields['directory'] . '_uninstall';
if (function_exists($function)) {
$function();
} else {
Session::addMessageAfterRedirect(
sprintf(__('Plugin %1$s has no uninstall function!'), $this->fields['name']),
true,
WARNING
);
}
$this->update([
'id' => $ID,
'state' => self::NOTINSTALLED,
]);
$this->unload($this->fields['directory']);
$type = INFO;
$message = sprintf(__('Plugin %1$s has been uninstalled!'), $this->fields['name']);
} else {
$message = sprintf(__('Plugin %1$s not found!'), $ID);
}
Session::addMessageAfterRedirect(
$message,
true,
$type
);
}
/**
* Install a plugin
*
* @param integer $ID ID of the plugin (The `id` field, not directory)
* @param array $params Additional params to pass to install hook.
*
* @return void
*
* @since 9.5.0 Added $param parameter
**/
function install($ID, array $params = []) {
global $DB;
$message = '';
$type = ERROR;
if ($this->getFromDB($ID)) {
// Clear locale cache to prevent errors while reloading plugin locales
$translation_cache = Config::getCache('cache_trans', 'core', true);
if ($translation_cache instanceof CacheInterface) {
$translation_cache->clear();
}
self::load($this->fields['directory'], true); // Load plugin hooks
$install_function = 'plugin_' . $this->fields['directory'] . '_install';
if (function_exists($install_function)) {
$DB->disableTableCaching(); //prevents issues on table/fieldExists upgrading from old versions
if ($install_function($params)) {
$type = INFO;
$check_function = 'plugin_' . $this->fields['directory'] . '_check_config';
$is_config_ok = !function_exists($check_function) || $check_function();
if ($is_config_ok) {
$this->update(['id' => $ID,
'state' => self::NOTACTIVATED]);
$message = sprintf(__('Plugin %1$s has been installed!'), $this->fields['name']);
$message .= '
' . str_replace(
'%activate_link',
Html::getSimpleForm(static::getFormURL(), ['action' => 'activate'],
mb_strtolower(_x('button', 'Enable')), ['id' => $ID], '', 'class="pointer"'),
__('Do you want to %activate_link it?')
);
} else {
$this->update(['id' => $ID,
'state' => self::TOBECONFIGURED]);
$message = sprintf(__('Plugin %1$s has been installed and must be configured!'), $this->fields['name']);
}
}
} else {
$type = WARNING;
$message = sprintf(__('Plugin %1$s has no install function!'), $this->fields['name']);
}
} else {
$message = sprintf(__('Plugin %1$s not found!'), $ID);
}
Session::addMessageAfterRedirect(
$message,
true,
$type
);
}
/**
* activate a plugin
*
* @param integer $ID ID of the plugin (The `id` field, not directory)
*
* @return boolean about success
**/
function activate($ID) {
global $PLUGIN_HOOKS;
if ($this->getFromDB($ID)) {
// Enable autoloader and load plugin hooks
self::load($this->fields['directory'], true);
// No activation if not CSRF compliant
if (!isset($PLUGIN_HOOKS['csrf_compliant'][$this->fields['directory']])
|| !$PLUGIN_HOOKS['csrf_compliant'][$this->fields['directory']]) {
Session::addMessageAfterRedirect(
sprintf(__('Plugin %1$s is not CSRF compliant!'), $this->fields['name']),
true,
ERROR
);
return false;
}
$function = 'plugin_' . $this->fields['directory'] . '_check_prerequisites';
if (function_exists($function)) {
ob_start();
$do_activate = $function();
$msg = '';
if (!$do_activate) {
$msg = '' . ob_get_contents() . '';
}
ob_end_clean();
if (!$do_activate) {
$this->unload($this->fields['directory']);
Session::addMessageAfterRedirect(
sprintf(__('Plugin prerequisites are not matching, it cannot be activated.') . ' ' . $msg, $this->fields['name']),
true,
ERROR
);
return false;
}
}
$function = 'plugin_' . $this->fields['directory'] . '_check_config';
if (!function_exists($function) || $function()) {
$this->update(['id' => $ID,
'state' => self::ACTIVATED]);
// Initialize session for the plugin
if (isset($PLUGIN_HOOKS['init_session'][$this->fields['directory']])
&& is_callable($PLUGIN_HOOKS['init_session'][$this->fields['directory']])) {
call_user_func($PLUGIN_HOOKS['init_session'][$this->fields['directory']]);
}
// Initialize profile for the plugin
if (isset($PLUGIN_HOOKS['change_profile'][$this->fields['directory']])
&& is_callable($PLUGIN_HOOKS['change_profile'][$this->fields['directory']])) {
call_user_func($PLUGIN_HOOKS['change_profile'][$this->fields['directory']]);
}
// reset menu
if (isset($_SESSION['glpimenu'])) {
unset($_SESSION['glpimenu']);
}
Session::addMessageAfterRedirect(
sprintf(__('Plugin %1$s has been activated!'), $this->fields['name']),
true,
INFO
);
return true;
} else {
$this->unload($this->fields['directory']);
Session::addMessageAfterRedirect(
sprintf(__('Plugin configuration must be done, it cannot be activated.') . ' ' . $msg, $this->fields['name']),
true,
ERROR
);
return false;
}
}
Session::addMessageAfterRedirect(
sprintf(__('Plugin %1$s not found!'), $ID),
true,
ERROR
);
return false;
}
/**
* Unactivate a plugin
*
* @param integer $ID ID of the plugin (The `id` field, not directory)
*
* @return boolean
**/
function unactivate($ID) {
if ($this->getFromDB($ID)) {
$this->update([
'id' => $ID,
'state' => self::NOTACTIVATED
]);
$this->unload($this->fields['directory']);
// reset menu
if (isset($_SESSION['glpimenu'])) {
unset($_SESSION['glpimenu']);
}
Session::addMessageAfterRedirect(
sprintf(__('Plugin %1$s has been deactivated!'), $this->fields['name']),
true,
INFO
);
return true;
}
Session::addMessageAfterRedirect(
sprintf(__('Plugin %1$s not found!'), $ID),
true,
ERROR
);
return false;
}
/**
* Unactivate all activated plugins for update process.
* This will prevent any plugin class to be available through autoloader.
**/
function unactivateAll() {
global $DB;
$DB->update(
$this->getTable(), [
'state' => self::NOTACTIVATED
], [
'state' => self::ACTIVATED
]
);
self::$activated_plugins = [];
self::$loaded_plugins = [];
// reset menu
if (isset($_SESSION['glpimenu'])) {
unset($_SESSION['glpimenu']);
}
}
/**
* clean a plugin
*
* @param $ID ID of the plugin
**/
function clean($ID) {
if ($this->getFromDB($ID)) {
// Clean crontask after "hard" remove
CronTask::Unregister($this->fields['directory']);
$this->unload($this->fields['directory']);
$this->delete(['id' => $ID]);
}
}
/**
* Is a plugin activated ?
*
* @param string $directory Plugin directory
*
* @return boolean
*/
function isActivated($directory) {
// Make a lowercase comparison, as sometime this function is called based on
// extraction of plugin name from a classname, which does not use same naming rules than directories.
$activated_plugins = array_map('strtolower', self::$activated_plugins);
if (in_array(strtolower($directory), $activated_plugins)) {
// If plugin is marked as activated, no need to query DB on this case.
return true;
}
// If plugin is not marked as activated, check on DB as it may have not been loaded yet.
if ($this->getFromDBbyDir($directory)) {
return ($this->fields['state'] == self::ACTIVATED) && $this->isLoadable($directory);
}
return false;
}
/**
* Is a plugin updatable ?
*
* @param string $directory Plugin directory
*
* @return boolean
*/
function isUpdatable($directory) {
// Make a lowercase comparison, as sometime this function is called based on
// extraction of plugin name from a classname, which does not use same naming rules than directories.
$activated_plugins = array_map('strtolower', self::$activated_plugins);
if (in_array(strtolower($directory), $activated_plugins)) {
// If plugin is marked as activated, no need to query DB on this case.
return false;
}
// If plugin is not marked as activated, check on DB as it may have not been loaded yet.
if ($this->getFromDBbyDir($directory)) {
return ($this->fields['state'] == self::NOTUPDATED) && $this->isLoadable($directory);
}
return false;
}
/**
* Is a plugin loadable ?
*
* @param string $directory Plugin directory
*
* @return boolean
*/
function isLoadable($directory) {
return !empty($this->getInformationsFromDirectory($directory));
}
/**
* Is a plugin installed ?
*
* @param string $directory Plugin directory
*
* @return boolean
*/
function isInstalled($directory) {
if ($this->isPluginLoaded($directory)) {
// If plugin is loaded, it is because it is installed and active. No need to query DB on this case.
return true;
}
// If plugin is not loaded, check on DB as plugins may have not been loaded yet.
if ($this->getFromDBbyDir($directory)) {
return in_array($this->fields['state'], [self::ACTIVATED, self::TOBECONFIGURED, self::NOTACTIVATED])
&& $this->isLoadable($directory);
}
}
/**
* Migrate itemtype from integer (0.72) to string (0.80)
*
* @param array $types Array of (num=>name) of type manage by the plugin
* @param array $glpitables Array of GLPI table name used by the plugin
* @param array $plugtables Array of Plugin table name which have an itemtype
*
* @return void
**/
static function migrateItemType($types = [], $glpitables = [], $plugtables = []) {
global $DB;
$typetoname = [0 => "",// For tickets
1 => "Computer",
2 => "NetworkEquipment",
3 => "Printer",
4 => "Monitor",
5 => "Peripheral",
6 => "Software",
7 => "Contact",
8 => "Supplier",
9 => "Infocom",
10 => "Contract",
11 => "CartridgeItem",
12 => "DocumentType",
13 => "Document",
14 => "KnowbaseItem",
15 => "User",
16 => "Ticket",
17 => "ConsumableItem",
18 => "Consumable",
19 => "Cartridge",
20 => "SoftwareLicense",
21 => "Link",
22 => "State",
23 => "Phone",
24 => "Device",
25 => "Reminder",
26 => "Stat",
27 => "Group",
28 => "Entity",
29 => "ReservationItem",
30 => "AuthMail",
31 => "AuthLDAP",
32 => "OcsServer",
33 => "RegistryKey",
34 => "Profile",
35 => "MailCollector",
36 => "Rule",
37 => "Transfer",
38 => "SavedSearch",
39 => "SoftwareVersion",
40 => "Plugin",
41 => "Item_Disk",
42 => "NetworkPort",
43 => "TicketFollowup",
44 => "Budget"];
// Filter tables that does not exists or does not contains an itemtype field.
// This kind of case exist when current method is called from plugins that based their
// logic on an old GLPI datamodel that may have changed upon time.
// see https://github.com/pluginsGLPI/order/issues/111
$glpitables = array_filter(
$glpitables,
function ($table) use ($DB) {
return $DB->tableExists($table) && $DB->fieldExists($table, 'itemtype');
}
);
//Add plugins types
$typetoname = self::doHookFunction("migratetypes", $typetoname);
foreach ($types as $num => $name) {
$typetoname[$num] = $name;
foreach ($glpitables as $table) {
$DB->updateOrDie(
$table, [
'itemtype' => $name,
], [
'itemtype' => $num
],
"update itemtype of table $table for $name"
);
}
}
if (in_array('glpi_infocoms', $glpitables) && count($types)) {
$entities = getAllDataFromTable('glpi_entities');
$entities[0] = "Root";
foreach ($types as $num => $name) {
$itemtable = getTableForItemType($name);
if (!$DB->tableExists($itemtable)) {
// Just for security, shouldn't append
continue;
}
$do_recursive = false;
if ($DB->fieldExists($itemtable, 'is_recursive')) {
$do_recursive = true;
}
foreach ($entities as $entID => $val) {
if ($do_recursive) {
// Non recursive ones
$sub_query = new \QuerySubQuery([
'SELECT' => 'id',
'FROM' => $itemtable,
'WHERE' => [
'entities_id' => $entID,
'is_recursive' => 0
]
]);
$DB->updateOrDie(
'glpi_infocoms', [
'entities_id' => $entID,
'is_recursive' => 0
], [
'itemtype' => $name,
'items_id' => $sub_query
],
"update entities_id and is_recursive=0 in glpi_infocoms for $name"
);
// Recursive ones
$sub_query = new \QuerySubQuery([
'SELECT' => 'id',
'FROM' => $itemtable,
'WHERE' => [
'entities_id' => $entID,
'is_recursive' => 1
]
]);
$DB->updateOrDie(
'glpi_infocoms', [
'entities_id' => $entID,
'is_recursive' => 1
], [
'itemtype' => $name,
'items_id' => $sub_query
],
"update entities_id and is_recursive=1 in glpi_infocoms for $name"
);
} else {
$sub_query = new \QuerySubQuery([
'SELECT' => 'id',
'FROM' => $itemtable,
'WHERE' => [
'entities_id' => $entID,
]
]);
$DB->updateOrDie(
'glpi_infocoms', [
'entities_id' => $entID
], [
'itemtype' => $name,
'items_id' => $sub_query
],
"update entities_id in glpi_infocoms for $name"
);
}
} // each entity
} // each plugin type
}
foreach ($typetoname as $num => $name) {
foreach ($plugtables as $table) {
$DB->updateOrDie(
$table, [
'itemtype' => $name
], [
'itemtype' => $num
],
"update itemtype of table $table for $name"
);
}
}
}
/**
* @param integer $width
**/
function showSystemInformations($width) {
// No need to translate, this part always display in english (for copy/paste to forum)
echo "\n
\n \n";
$plug = new Plugin();
$pluglist = $plug->find([], "name, directory");
foreach ($pluglist as $plugin) {
$msg = substr(str_pad($plugin['directory'], 30), 0, 20).
" Name: ".Toolbox::substr(str_pad($plugin['name'], 40), 0, 30).
" Version: ".str_pad($plugin['version'], 10).
" State: ";
$state = $plug->isLoadable($plugin['directory']) ? $plugin['state'] : self::TOBECLEANED;
$msg .= self::getState($state);
echo wordwrap("\t".$msg."\n", $width, "\n\t\t");
}
echo "\n