Sindbad~EG File Manager
<?php
/**
* -------------------------------------------------------------------------
* Fields plugin for GLPI
* -------------------------------------------------------------------------
*
* LICENSE
*
* This file is part of Fields.
*
* Fields is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Fields is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Fields. If not, see <http://www.gnu.org/licenses/>.
* -------------------------------------------------------------------------
* @copyright Copyright (C) 2013-2022 by Fields plugin team.
* @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html
* @link https://github.com/pluginsGLPI/fields
* -------------------------------------------------------------------------
*/
use Glpi\Toolbox\Sanitizer;
class PluginFieldsContainer extends CommonDBTM
{
use Glpi\Features\Clonable;
public static $rightname = 'config';
public static function canCreate()
{
return self::canUpdate();
}
public static function canPurge()
{
return self::canUpdate();
}
public static function titleList()
{
echo "<div class='center'><a class='vsubmit' href='regenerate_files.php'><i class='pointer fa fa-refresh'></i> " .
__("Regenerate container files", "fields") . "</a> <a class='vsubmit' href='export_to_yaml.php'><i class='pointer fa fa-refresh'></i> " .
__("Export to YAML", "fields") . "</a></div><br>";
}
/**
* Install or update containers
*
* @param Migration $migration Migration instance
* @param string $version Plugin current version
*
* @return boolean
*/
public static function install(Migration $migration, $version)
{
global $DB;
$default_charset = DBConnection::getDefaultCharset();
$default_collation = DBConnection::getDefaultCollation();
$default_key_sign = DBConnection::getDefaultPrimaryKeySignOption();
$table = self::getTable();
if (!$DB->tableExists($table)) {
$migration->displayMessage(sprintf(__("Installing %s"), $table));
$query = "CREATE TABLE IF NOT EXISTS `$table` (
`id` INT {$default_key_sign} NOT NULL auto_increment,
`name` VARCHAR(255) DEFAULT NULL,
`label` VARCHAR(255) DEFAULT NULL,
`itemtypes` LONGTEXT DEFAULT NULL,
`type` VARCHAR(255) DEFAULT NULL,
`subtype` VARCHAR(255) DEFAULT NULL,
`entities_id` INT {$default_key_sign} NOT NULL DEFAULT '0',
`is_recursive` TINYINT NOT NULL DEFAULT '0',
`is_active` TINYINT NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `entities_id` (`entities_id`)
) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;";
$DB->query($query) or die($DB->error());
}
// multiple itemtype for one container
if (!$DB->fieldExists($table, "itemtypes")) {
$migration->changeField($table, 'itemtype', 'itemtypes', 'longtext');
$migration->migrationOneTable($table);
$query = "UPDATE `$table` SET `itemtypes` = CONCAT('[\"', `itemtypes`, '\"]')";
$DB->query($query) or die($DB->error());
}
//add display preferences for this class
$d_pref = new DisplayPreference();
$found = $d_pref->find(['itemtype' => __CLASS__]);
if (count($found) == 0) {
for ($i = 2; $i <= 5; $i++) {
$DB->query("REPLACE INTO glpi_displaypreferences VALUES
(NULL, '" . __CLASS__ . "', $i, " . ($i - 1) . ", 0)");
}
}
if (!$DB->fieldExists($table, "subtype")) {
$migration->addField($table, 'subtype', 'VARCHAR(255) DEFAULT NULL', ['after' => 'type']);
$migration->migrationOneTable($table);
}
// Fix containers names that were generated prior to Fields 1.9.2.
$bad_named_containers = $DB->request(
[
'FROM' => self::getTable(),
'WHERE' => [
'name' => [
'REGEXP',
$DB->escape('\d+')
],
],
]
);
if ($bad_named_containers->count() > 0) {
$migration->displayMessage(__("Fix container names", "fields"));
$toolbox = new PluginFieldsToolbox();
foreach ($bad_named_containers as $container) {
$old_name = $container['name'];
// Update container name
$new_name = $toolbox->getSystemNameFromLabel($container['label']);
foreach (json_decode($container['itemtypes']) as $itemtype) {
while (strlen(getTableForItemType(self::getClassname($itemtype, $new_name))) > 64) {
// limit tables names to 64 chars (MySQL limit)
$new_name = substr($new_name, 0, -1);
}
}
$container['name'] = $new_name;
$container_obj = new PluginFieldsContainer();
$container_obj->update(
$container,
false
);
// Rename container tables and itemtype if needed
foreach (json_decode($container['itemtypes']) as $itemtype) {
$migration->renameItemtype(
self::getClassname($itemtype, $old_name),
self::getClassname($itemtype, $new_name)
);
}
}
}
//Computer OS tab is no longer part of computer object. Moving to main
$ostab = self::findContainer(Computer::getType(), 'domtab', Computer::getType() . '$1');
if ($ostab) {
//check if we already have a container on Computer main tab
$comptab = self::findContainer(Computer::getType(), 'dom');
if ($comptab) {
$oscontainer = new PluginFieldsContainer();
$oscontainer->getFromDB($ostab);
$compcontainer = new PluginFieldsContainer();
$compcontainer->getFromDB($comptab);
$fields = new PluginFieldsField();
$fields = $fields->find(['plugin_fields_containers_id' => $ostab]);
$classname = self::getClassname(Computer::getType(), $oscontainer->fields['name']);
$osdata = new $classname();
$classname = self::getClassname(Computer::getType(), $compcontainer->fields['name']);
$compdata = new $classname();
$fieldnames = [];
//add fields to compcontainer
foreach ($fields as $field) {
$newname = $field['name'];
$compfields = $fields->find(['plugin_fields_containers_id' => $comptab, 'name' => $newname]);
if ($compfields) {
$newname = $newname . '_os';
$DB->query("UPDATE glpi_plugin_fields_fields SET name='$newname' WHERE name='{$field['name']}' AND plugin_fields_containers_id='$ostab'");
}
$compdata::addField($newname, $field['type']);
$fieldnames[$field['name']] = $newname;
}
$sql = "UPDATE glpi_plugin_fields_fields SET plugin_fields_containers_id='$comptab' WHERE plugin_fields_containers_id='$ostab'";
$DB->query($sql);
$DB->query("DELETE FROM glpi_plugin_fields_containers WHERE id='$ostab'");
//migrate existing data
$existings = $osdata->find();
foreach ($existings as $existing) {
$data = [];
foreach ($fieldnames as $oldname => $newname) {
$data[$newname] = $existing[$oldname];
}
$compdata->add($data);
}
//drop old table
$DB->query("DROP TABLE " . $osdata::getTable());
} else {
$sql = "UPDATE glpi_plugin_fields_containers SET type='dom', subtype=NULL WHERE id='$ostab'";
$comptab = $ostab;
$DB->query($sql);
}
}
$migration->displayMessage(__("Updating generated containers files", "fields"));
$obj = new self();
$containers = $obj->find();
// -> 0.90-1.3: generated class moved
// OLD path: GLPI_ROOT."/plugins/fields/inc/$class_filename"
// NEW path: PLUGINFIELDS_CLASS_PATH . "/$class_filename"
foreach ($containers as $container) {
//First, drop old fields from plugin directories
$itemtypes = !empty($container['itemtypes'])
? json_decode($container['itemtypes'], true)
: [];
foreach ($itemtypes as $itemtype) {
$sysname = self::getSystemName($itemtype, $container['name']);
$class_filename = $sysname . ".class.php";
if (file_exists(PLUGINFIELDS_DIR . "/inc/$class_filename")) {
unlink(PLUGINFIELDS_DIR . "/inc/$class_filename");
}
$injclass_filename = $sysname . "injection.class.php";
if (file_exists(PLUGINFIELDS_DIR . "/inc/$injclass_filename")) {
unlink(PLUGINFIELDS_DIR . "/inc/$injclass_filename");
}
}
}
// Regenerate files and install missing tables
foreach ($containers as $container) {
self::create($container);
}
return true;
}
public static function uninstall()
{
global $DB;
//uninstall container table and class
$obj = new self();
$containers = $obj->find();
foreach ($containers as $container) {
$obj->delete(['id' => $container['id']]);
}
//drop global container table
$DB->query("DROP TABLE IF EXISTS `" . self::getTable() . "`");
//delete display preferences for this item
$pref = new DisplayPreference();
$pref->deleteByCriteria([
'itemtype' => __CLASS__
]);
return true;
}
// phpcs:ignore PSR1.Methods.CamelCapsMethodName
public function post_getEmpty()
{
$this->fields['is_active'] = 1;
$this->fields['is_recursive'] = 1;
}
public function rawSearchOptions()
{
$tab = [];
$tab[] = [
'id' => 1,
'table' => self::getTable(),
'field' => 'name',
'name' => __("Name"),
'datatype' => 'itemlink',
'itemlink_type' => self::getType(),
'massiveaction' => false,
];
$tab[] = [
'id' => 2,
'table' => self::getTable(),
'field' => 'label',
'name' => __("Label"),
'massiveaction' => false,
'autocomplete' => true,
];
$tab[] = [
'id' => 3,
'table' => self::getTable(),
'field' => 'itemtypes',
'name' => __("Associated item type"),
'datatype' => 'specific',
'massiveaction' => false,
'nosearch' => true,
];
$tab[] = [
'id' => 4,
'table' => self::getTable(),
'field' => 'type',
'name' => __("Type"),
'searchtype' => ['equals', 'notequals'],
'massiveaction' => false,
];
$tab[] = [
'id' => 5,
'table' => self::getTable(),
'field' => 'is_active',
'name' => __("Active"),
'datatype' => 'bool',
'searchtype' => ['equals', 'notequals'],
];
$tab[] = [
'id' => 6,
'table' => 'glpi_entities',
'field' => 'completename',
'name' => __("Entity"),
'massiveaction' => false,
'datatype' => 'dropdown',
];
$tab[] = [
'id' => 7,
'table' => self::getTable(),
'field' => 'is_recursive',
'name' => __("Child entities"),
'massiveaction' => false,
'datatype' => 'bool',
];
$tab[] = [
'id' => 8,
'table' => self::getTable(),
'field' => 'id',
'name' => __("ID"),
'datatype' => 'number',
'massiveaction' => false,
];
return $tab;
}
public static function getSpecificValueToDisplay($field, $values, array $options = [])
{
if (!is_array($values)) {
$values = [$field => $values];
}
switch ($field) {
case 'type':
$types = self::getTypes();
return $types[$values[$field]];
case 'itemtypes':
$types = json_decode($values[$field]);
$obj = '';
$count = count($types);
$i = 1;
foreach ($types as $type) {
// prevent usage of plugin class if not loaded
if (!class_exists($type)) {
continue;
}
$name_type = getItemForItemtype($type);
$obj .= $name_type->getTypeName(2);
if ($count > $i) {
$obj .= ", ";
}
$i++;
}
return $obj;
}
}
public function getValueToSelect($field_id_or_search_options, $name = '', $values = '', $options = [])
{
switch ($field_id_or_search_options['table'] . '.' . $field_id_or_search_options['field']) {
// For searchoption "Type"
case $this->getTable() . '.type':
$options['display'] = false;
return Dropdown::showFromArray($name, self::getTypes(), $options);
case $this->getTable() . '.itemtypes':
$options['display'] = false;
return Dropdown::showFromArray($name, self::getItemtypes(), $options);
}
return parent::getValueToSelect($field_id_or_search_options, $name, $values, $options);
}
public function defineTabs($options = [])
{
$ong = [];
$this->addDefaultFormTab($ong);
$this->addStandardTab('PluginFieldsField', $ong, $options);
$this->addStandardTab('PluginFieldsStatusOverride', $ong, $options);
$this->addStandardTab('PluginFieldsProfile', $ong, $options);
$this->addStandardTab('PluginFieldsContainerDisplayCondition', $ong, $options);
$this->addStandardTab('PluginFieldsLabelTranslation', $ong, $options);
return $ong;
}
public function prepareInputForAdd($input)
{
if (!isset($input['itemtypes'])) {
Session::AddMessageAfterRedirect(
__(
"You cannot add block without associated element type",
"fields"
),
false,
ERROR
);
return false;
}
if (!is_array($input['itemtypes'])) {
$input['itemtypes'] = [$input['itemtypes']];
}
if ($input['type'] === "dom") {
//check for already exist dom container with this itemtype
$found = $this->find(['type' => 'dom']);
if (count($found) > 0) {
foreach (array_column($found, 'itemtypes') as $founditemtypes) {
foreach (json_decode($founditemtypes) as $founditemtype) {
if (in_array($founditemtype, $input['itemtypes'])) {
Session::AddMessageAfterRedirect(__("You cannot add several blocks with type 'Insertion in the form' on same object", "fields"), false, ERROR);
return false;
}
}
}
}
}
if ($input['type'] === "domtab") {
//check for already exist domtab container with this itemtype on this tab
$found = $this->find(['type' => 'domtab', 'subtype' => $input['subtype']]);
if (count($found) > 0) {
foreach (array_column($found, 'itemtypes') as $founditemtypes) {
foreach (json_decode($founditemtypes) as $founditemtype) {
if (in_array($founditemtype, $input['itemtypes'])) {
Session::AddMessageAfterRedirect(__("You cannot add several blocks with type 'Insertion in the form of a specific tab' on same object tab", "fields"), false, ERROR);
return false;
}
}
}
}
}
$toolbox = new PluginFieldsToolbox();
$input['name'] = $toolbox->getSystemNameFromLabel($input['label']);
//reject adding when container name is too long for mysql table name
foreach ($input['itemtypes'] as $itemtype) {
$tmp = getTableForItemType(self::getClassname($itemtype, $input['name']));
if (strlen($tmp) > 64) {
Session::AddMessageAfterRedirect(
__("Container name is too long for database (digits in name are replaced by characters, try to remove them)", 'fields'),
false,
ERROR
);
return false;
}
}
//check for already existing container with same name
$found = $this->find(['name' => $input['name']]);
if (count($found) > 0) {
foreach (array_column($found, 'itemtypes') as $founditemtypes) {
foreach (json_decode($founditemtypes) as $founditemtype) {
if (in_array($founditemtype, $input['itemtypes'])) {
Session::AddMessageAfterRedirect(__("You cannot add several blocs with identical name on same object", "fields"), false, ERROR);
return false;
}
}
}
}
$input['itemtypes'] = isset($input['itemtypes'])
? Sanitizer::dbEscape(json_encode($input['itemtypes']))
: null;
return $input;
}
// phpcs:ignore PSR1.Methods.CamelCapsMethodName
public function post_addItem()
{
if (!isset($this->input['clone']) || !$this->input['clone']) {
//create profiles associated to this container
PluginFieldsProfile::createForContainer($this);
//Create label translation
PluginFieldsLabelTranslation::createForItem($this);
}
self::create($this->fields);
}
public static function create($fields)
{
//create class file
if (!self::generateTemplate($fields)) {
return false;
}
foreach (json_decode($fields['itemtypes']) as $itemtype) {
//install table for receive field
$classname = self::getClassname($itemtype, $fields['name']);
$classname::install();
}
}
public static function generateTemplate($fields)
{
$itemtypes = strlen($fields['itemtypes']) > 0
? json_decode($fields['itemtypes'], true)
: [];
foreach ($itemtypes as $itemtype) {
// prevent usage of plugin class if not loaded
if (!class_exists($itemtype)) {
continue;
}
$sysname = self::getSystemName($itemtype, $fields['name']);
$classname = self::getClassname($itemtype, $fields['name']);
$template_class = file_get_contents(PLUGINFIELDS_DIR . "/templates/container.class.tpl");
$template_class = str_replace("%%CLASSNAME%%", $classname, $template_class);
$template_class = str_replace("%%ITEMTYPE%%", $itemtype, $template_class);
$template_class = str_replace("%%CONTAINER%%", $fields['id'], $template_class);
$template_class = str_replace("%%ITEMTYPE_RIGHT%%", $itemtype::$rightname, $template_class);
$class_filename = $sysname . ".class.php";
if (file_put_contents(PLUGINFIELDS_CLASS_PATH . "/$class_filename", $template_class) === false) {
Toolbox::logDebug("Error : class file creation - $class_filename");
return false;
}
// Generate Datainjection files
$template_class = file_get_contents(PLUGINFIELDS_DIR . "/templates/injection.class.tpl");
$template_class = str_replace("%%CLASSNAME%%", $classname, $template_class);
$template_class = str_replace("%%ITEMTYPE%%", $itemtype, $template_class);
$template_class = str_replace("%%CONTAINER_ID%%", $fields['id'], $template_class);
$template_class = str_replace("%%CONTAINER_NAME%%", $fields['label'], $template_class);
$class_filename = $sysname . "injection.class.php";
if (file_put_contents(PLUGINFIELDS_CLASS_PATH . "/$class_filename", $template_class) === false) {
Toolbox::logDebug("Error : datainjection class file creation - $class_filename");
return false;
}
}
return true;
}
// phpcs:ignore PSR1.Methods.CamelCapsMethodName
public function pre_deleteItem()
{
global $DB;
$_SESSION['delete_container'] = true;
foreach (json_decode($this->fields['itemtypes']) as $itemtype) {
$classname = self::getClassname($itemtype, $this->fields['name']);
$sysname = self::getSystemName($itemtype, $this->fields['name']);
$class_filename = $sysname . ".class.php";
$injection_filename = $sysname . "injection.class.php";
//delete fields
$field_obj = new PluginFieldsField();
$field_obj->deleteByCriteria([
'plugin_fields_containers_id' => $this->fields['id']
]);
//delete display condition
$field_obj = new PluginFieldsContainerDisplayCondition();
$field_obj->deleteByCriteria([
'plugin_fields_containers_id' => $this->fields['id']
]);
//delete profiles
$profile_obj = new PluginFieldsProfile();
$profile_obj->deleteByCriteria([
'plugin_fields_containers_id' => $this->fields['id']
]);
//delete label translations
$translation_obj = new PluginFieldsLabelTranslation();
$translation_obj->deleteByCriteria([
'itemtype' => self::getType(),
'items_id' => $this->fields['id']
]);
//delete table
if (class_exists($classname)) {
$classname::uninstall();
} else {
//class does not exists; try to remove any existing table
$tablename = getTableForItemType($classname);
$DB->query("DROP TABLE IF EXISTS `$tablename`");
}
//clean session
unset($_SESSION['delete_container']);
//remove file
if (file_exists(PLUGINFIELDS_CLASS_PATH . "/$class_filename")) {
unlink(PLUGINFIELDS_CLASS_PATH . "/$class_filename");
}
if (file_exists(PLUGINFIELDS_CLASS_PATH . "/$injection_filename")) {
unlink(PLUGINFIELDS_CLASS_PATH . "/$injection_filename");
}
}
return true;
}
public static function preItemPurge($item)
{
$itemtype = get_class($item);
$containers = new self();
$founded_containers = $containers->find();
foreach ($founded_containers as $container) {
$itemtypes = json_decode($container['itemtypes']);
if (in_array($itemtype, $itemtypes)) {
$classname = 'PluginFields' . $itemtype . getSingular($container['name']);
$fields = new $classname();
$fields->deleteByCriteria(['items_id' => $item->fields['id']], true);
}
}
return true;
}
public static function getTypeName($nb = 0)
{
return __("Block", "fields");
}
public function showForm($ID, $options = [])
{
$this->initForm($ID, $options);
if (!$this->isNewID($ID)) {
$btn_url = Plugin::getWebDir('fields') . '/front/export_to_yaml.php?id=' . $ID;
$btn_label = __("Export to YAML", "fields");
$export_btn = <<<HTML
<a href="{$btn_url}" class="btn btn-ghost-secondary"
title="{$btn_label}"
data-bs-toggle="tooltip" data-bs-placement="bottom">
<i class="fas fa-file-export fa-lg"></i>
</a>
HTML;
$options['header_toolbar'] = [$export_btn];
}
$this->showFormHeader($options);
$rand = mt_rand();
echo "<tr>";
echo "<td width='20%'>" . __("Label") . " : </td>";
echo "<td width='30%'>";
echo Html::input(
'label',
[
'value' => $this->fields['label'],
]
);
echo "</td>";
echo "<td width='20%'> </td>";
echo "<td width='30%'> </td>";
echo "</tr>";
echo "<tr>";
echo "<td>" . __("Type") . " : </td>";
echo "<td>";
if ($ID > 0) {
$types = self::getTypes();
echo $types[$this->fields["type"]];
} else {
Dropdown::showFromArray(
'type',
self::getTypes(),
[
'value' => $this->fields["type"],
'rand' => $rand
]
);
Ajax::updateItemOnSelectEvent(
"dropdown_type$rand",
"itemtypes_$rand",
"../ajax/container_itemtypes_dropdown.php",
[
'type' => '__VALUE__',
'itemtype' => $this->fields["itemtypes"],
'subtype' => $this->fields['subtype'],
'rand' => $rand
]
);
}
echo "</td>";
echo "<td>" . __("Associated item type") . " : </td>";
echo "<td>";
if ($ID > 0) {
$types = json_decode($this->fields['itemtypes']);
$obj = '';
$count = count($types);
$i = 1;
foreach ($types as $type) {
// prevent usage of plugin class if not loaded
if (!class_exists($type)) {
continue;
}
$name_type = getItemForItemtype($type);
$obj .= $name_type->getTypeName(2);
if ($count > $i) {
$obj .= ", ";
}
$i++;
}
echo $obj;
} else {
echo " <span id='itemtypes_$rand'>";
self::showFormItemtype([
'rand' => $rand,
'subtype' => $this->fields['subtype']
]);
echo "</span>";
}
echo "</td>";
echo "</tr>";
$display = "style='display:none'";
if (!empty($this->fields["subtype"])) {
$display = "";
}
echo "<tr id='tab_tr' $display>";
echo "<td colspan='2'></td>";
echo "<td>" . __("Tab", "fields") . " : </td>";
echo "<td>";
echo " <span id='subtype_$rand'></span>";
if ($ID > 0 && !empty($this->fields["subtype"])) {
$itemtypes = json_decode($this->fields["itemtypes"], true);
$itemtype = array_shift($itemtypes);
$item = new $itemtype();
$item->getEmpty();
$tabs = self::getSubtypes($item);
echo $tabs[$this->fields["subtype"]];
}
echo "</td>";
echo "</tr>";
echo "<tr>";
echo "<td>" . __("Active") . " : </td>";
echo "<td>";
Dropdown::showYesNo("is_active", $this->fields["is_active"]);
echo "</td>";
echo "</tr>";
$this->showFormButtons($options);
return true;
}
public static function showFormItemtype($params = [])
{
$is_domtab = isset($params['type']) && $params['type'] == 'domtab';
$rand = $params['rand'];
Dropdown::showFromArray(
"itemtypes",
self::getItemtypes($is_domtab),
[
'rand' => $rand,
'multiple' => !$is_domtab,
'width' => 200,
'display_emptychoice' => $is_domtab
]
);
if ($is_domtab) {
Ajax::updateItemOnSelectEvent(
["dropdown_type$rand", "dropdown_itemtypes$rand"],
"subtype_$rand",
"../ajax/container_subtype_dropdown.php",
[
'type' => '__VALUE0__',
'itemtype' => '__VALUE1__',
'subtype' => $params["subtype"],
'rand' => $rand
]
);
}
}
/**
* Show subtype selection form
*
* @param array $params Parameters
* @param boolean $display Whether to display or not; defaults to false
*
* @return string|void
*/
public static function showFormSubtype($params, $display = false)
{
$out = "<script type='text/javascript'>jQuery('#tab_tr').hide();</script>";
if (isset($params['type']) && $params['type'] == "domtab") {
if (class_exists($params['itemtype'])) {
$item = new $params['itemtype']();
$item->getEmpty();
$tabs = self::getSubtypes($item);
if (count($tabs)) {
// delete Log of array (don't work with this tab)
$tabs_to_remove = ['Log$1', 'Document_Item$1'];
foreach ($tabs_to_remove as $tab_to_remove) {
if (isset($tabs[$tab_to_remove])) {
unset($tabs[$tab_to_remove]);
}
}
// For delete <sup class='tab_nb'>number</sup> :
foreach ($tabs as &$value) {
$results = [];
if (preg_match_all('#<sup.*>(.+)</sup>#', $value, $results)) {
$value = str_replace($results[0][0], "", $value);
}
}
if (!isset($params['subtype'])) {
$params['subtype'] = null;
}
$out .= Dropdown::showFromArray(
'subtype',
$tabs,
['value' => $params['subtype'],
'width' => '100%',
'display' => false
]
);
$out .= "<script type='text/javascript'>jQuery('#tab_tr').show();</script>";
}
}
}
if ($display === false) {
return $out;
} else {
echo $out;
}
}
/**
* Get supported item types
*
* @param boolean $is_domtab Domtab or not
*
* @return array
*/
public static function getItemtypes($is_domtab)
{
$all_itemtypes = PluginFieldsToolbox::getGlpiItemtypes();
if ($is_domtab) {
// Filter items that do not have tab handled
foreach ($all_itemtypes as $section => $itemtypes) {
$all_itemtypes[$section] = array_filter(
$itemtypes,
function ($itemtype) {
return count(self::getSubtypes($itemtype)) > 0;
},
ARRAY_FILTER_USE_KEY
);
}
// Filter groupts that do not have items handled
$all_itemtypes = array_filter($all_itemtypes);
}
return $all_itemtypes;
}
public static function getTypes()
{
return [
'tab' => __("Add tab", "fields"),
'dom' => __("Insertion in the form (before save button)", "fields"),
'domtab' => __("Insertion in the form of a specific tab (before save button)", "fields")
];
}
public static function getEntries($type = 'tab', $full = false)
{
global $DB;
$condition = [
'is_active' => 1,
];
if ($type !== "all") {
$condition[] = ['type' => $type];
}
if (!$DB->tableExists(self::getTable())) {
return false;
}
$itemtypes = [];
$container = new self();
$profile = new PluginFieldsProfile();
$found = $container->find($condition, 'label');
foreach ($found as $item) {
//entities restriction
if (!in_array($item['entities_id'], $_SESSION['glpiactiveentities'])) {
if ($item['is_recursive'] == 1) {
$entities = getSonsOf("glpi_entities", $item['entities_id']);
if (count(array_intersect($entities, $_SESSION['glpiactiveentities'])) == 0) {
continue;
}
} else {
continue;
}
}
if (Session::isCron() || !isset($_SESSION['glpiactiveprofile']['id'])) {
continue;
}
//profiles restriction
$found = $profile->find(['profiles_id' => $_SESSION['glpiactiveprofile']['id'],
'plugin_fields_containers_id' => $item['id'],
'right' => ['>=', READ]
]);
$first_found = array_shift($found);
if (!$first_found || $first_found['right'] == null || $first_found['right'] == 0) {
continue;
}
$jsonitemtypes = json_decode($item['itemtypes']);
//show more info or not
foreach ($jsonitemtypes as $v) {
if ($full) {
//check for translation
$item['itemtype'] = self::getType();
$label = PluginFieldsLabelTranslation::getLabelFor($item);
$itemtypes[$v][$item['name']] = $label;
} else {
$itemtypes[] = $v;
}
}
}
return $itemtypes;
}
public static function getUsedItemtypes($type = 'all', $must_be_active = false)
{
global $DB;
$itemtypes = [];
$where = $type == 'all' ? '1=1' : ('type = "' . $type . '"');
if ($must_be_active) {
$where .= ' AND is_active = 1';
}
$query = 'SELECT DISTINCT `itemtypes` FROM `glpi_plugin_fields_containers` WHERE ' . $where;
$result = $DB->query($query);
while (list($data) = $DB->fetchArray($result)) {
$jsonitemtype = json_decode($data);
$itemtypes = array_merge($itemtypes, $jsonitemtype);
}
return $itemtypes;
}
public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0)
{
$itemtypes = self::getEntries('tab', true);
if (isset($itemtypes[$item->getType()])) {
$tabs_entries = [];
$container = new self();
foreach ($itemtypes[$item->getType()] as $tab_name => $tab_label) {
// needs to check if entity of item is in hierachy of $tab_name
foreach ($container->find(['is_active' => 1, 'name' => $tab_name]) as $data) {
$dataitemtypes = json_decode($data['itemtypes']);
if (in_array(get_class($item), $dataitemtypes) != false) {
$entities = [$data['entities_id']];
if ($data['is_recursive']) {
$entities = getSonsOf(getTableForItemType('Entity'), $data['entities_id']);
}
if (!$item->isEntityAssign() || in_array($item->fields['entities_id'], $entities)) {
$display_condition = new PluginFieldsContainerDisplayCondition();
if ($display_condition->computeDisplayContainer($item, $data['id'])) {
$tabs_entries[$tab_name] = $tab_label;
}
}
}
}
}
return $tabs_entries;
}
}
public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0)
{
if ($withtemplate) {
//Do not display tab from template or from item created from template
return [];
}
//retrieve container for current tab
$container = new self();
$found_c = $container->find(['type' => 'tab', 'name' => $tabnum, 'is_active' => 1]);
foreach ($found_c as $data) {
$dataitemtypes = json_decode($data['itemtypes']);
if (in_array(get_class($item), $dataitemtypes) != false) {
return PluginFieldsField::showForTabContainer($data['id'], $item);
}
}
}
/**
* Insert values submited by fields container
*
* @param array $data data posted
* @param string $itemtype Item type
* @param boolean $massiveaction Is a massive action
*
* @return boolean
*/
public function updateFieldsValues($data, $itemtype, $massiveaction = false)
{
if (self::validateValues($data, $itemtype, $massiveaction) === false) {
return false;
}
$container_obj = new PluginFieldsContainer();
$container_obj->getFromDB($data['plugin_fields_containers_id']);
$items_id = $data['items_id'];
$classname = self::getClassname($itemtype, $container_obj->fields['name']);
//check if data already inserted
$obj = new $classname();
$found = $obj->find(['items_id' => $items_id]);
if (empty($found)) {
// add fields data
$obj->add($data);
//construct history on itemtype object (Historical tab)
self::constructHistory(
$data['plugin_fields_containers_id'],
$items_id,
$itemtype,
$data
);
} else {
$first_found = array_pop($found);
$data['id'] = $first_found['id'];
$obj->update($data);
//construct history on itemtype object (Historical tab)
self::constructHistory(
$data['plugin_fields_containers_id'],
$items_id,
$itemtype,
$data,
$first_found
);
}
return true;
}
/**
* Add log in "itemtype" object on fields values update
* @param int $containers_id container id
* @param int $items_id item id
* @param string $itemtype item type
* @param array $data values send by update form
* @param array $old_values old values, if empty -> values add
* @return void
*/
public static function constructHistory(
$containers_id,
$items_id,
$itemtype,
$data,
$old_values = []
) {
// Don't log few itemtypes
$obj = new $itemtype();
if ($obj->dohistory == false) {
return;
}
//get searchoptions
$searchoptions = self::getAddSearchOptions($itemtype, $containers_id);
//define non-data keys
$blacklist_k = [
'plugin_fields_containers_id' => 0,
'items_id' => 0,
'itemtype' => $itemtype,
'update_fields_values' => 0,
'_glpi_csrf_token' => 0
];
//remove non-data keys
$data = array_diff_key($data, $blacklist_k);
//add/update values condition
if (empty($old_values)) {
// -- add new item --
foreach ($data as $key => $value) {
//log only not empty values
if (!empty($value)) {
//prepare log
$changes = [0, "N/A", $value];
//find searchoption
foreach ($searchoptions as $id_search_option => $searchoption) {
if ($searchoption['linkfield'] == $key) {
$changes[0] = $id_search_option;
//manage dropdown values
if ($searchoption['datatype'] === 'dropdown') {
$changes = [$id_search_option,
"",
Dropdown::getDropdownName($searchoption['table'], $value)
];
}
//manage bool dropdown values
if ($searchoption['datatype'] === 'bool') {
$changes = [$id_search_option, "", Dropdown::getYesNo($value)];
}
}
}
//add log
Log::history($items_id, $itemtype, $changes);
}
}
} else {
// -- update existing item --
//find changes
$updates = [];
foreach ($old_values as $key => $old_value) {
if (
!isset($data[$key])
|| empty($old_value) && empty($data[$key])
|| $old_value !== '' && $data[$key] == 'NULL'
) {
continue;
}
if ($data[$key] !== $old_value) {
$updates[$key] = [0, $old_value ?? '', $data[$key]];
}
}
//for all change find searchoption
foreach ($updates as $key => $changes) {
foreach ($searchoptions as $id_search_option => $searchoption) {
if ($searchoption['linkfield'] == $key) {
$changes[0] = $id_search_option;
//manage dropdown values
if ($searchoption['datatype'] === 'dropdown') {
$changes[1] = Dropdown::getDropdownName($searchoption['table'], $changes[1]);
$changes[2] = Dropdown::getDropdownName($searchoption['table'], $changes[2]);
}
if ($searchoption['datatype'] === 'bool') {
$changes[1] = Dropdown::getYesNo($changes[1]);
$changes[2] = Dropdown::getYesNo($changes[2]);
}
}
}
//add log
Log::history($items_id, $itemtype, $changes);
}
}
}
/**
* check data inserted
* display a message when not ok
*
* @param array $data Data send by form
* @param string $itemtype Item type
* @param boolean $massiveaction ?
*
* @return boolean
*/
public static function validateValues($data, $itemtype, $massiveaction)
{
global $DB;
$valid = true;
$empty_errors = [];
$number_errors = [];
$container = new self();
$container->getFromDB($data['plugin_fields_containers_id']);
$field_obj = new PluginFieldsField();
$fields = $field_obj->find([
'plugin_fields_containers_id' => $data['plugin_fields_containers_id']
]);
// Apply status overrides
$status_field_name = PluginFieldsStatusOverride::getStatusFieldName($itemtype);
$status_overrides = $data[$status_field_name] !== null
? PluginFieldsStatusOverride::getOverridesForItemtypeAndStatus($container->getID(), $itemtype, $data[$status_field_name])
: [];
foreach ($status_overrides as $status_override) {
if (isset($fields[$status_override['plugin_fields_fields_id']])) {
$fields[$status_override['plugin_fields_fields_id']]['is_readonly'] = $status_override['is_readonly'];
$fields[$status_override['plugin_fields_fields_id']]['mandatory'] = $status_override['mandatory'];
}
}
foreach ($fields as $field) {
if (!$field['is_active']) {
continue;
}
if ($field['type'] == "yesno" || $field['type'] == "header") {
continue;
}
$name = $field['name'];
$value = null;
if ($field['type'] == "glpi_item") {
$itemtype_key = sprintf('itemtype_%s', $name);
$items_id_key = sprintf('items_id_%s', $name);
if (
isset($data[$itemtype_key], $data[$items_id_key])
&& is_a($data[$itemtype_key], CommonDBTM::class, true)
&& $data[$items_id_key] > 0
) {
$glpi_item = new $data[$itemtype_key]();
$value = $glpi_item->getFromDB($data[$items_id_key]) ? $data[$items_id_key] : null;
}
} elseif (isset($data[$name])) {
$value = $data[$name];
} else if (isset($data['plugin_fields_' . $name . 'dropdowns_id'])) {
$value = $data['plugin_fields_' . $name . 'dropdowns_id'];
} else if ($field['mandatory'] == 1 && isset($data['items_id'])) {
$tablename = getTableForItemType(self::getClassname($itemtype, $container->fields['name']));
$query = "SELECT * FROM `$tablename` WHERE
`itemtype`='$itemtype'
AND `items_id`='{$data['items_id']}'
AND `plugin_fields_containers_id`='{$data['plugin_fields_containers_id']}'";
$db_result = [];
if ($result = $DB->query($query)) {
$db_result = $DB->fetchAssoc($result);
if (isset($db_result[$name])) {
$value = $db_result[$name];
}
}
} else {
if ($massiveaction) {
continue;
}
}
//translate label
$field['itemtype'] = PluginFieldsField::getType();
$field['label'] = PluginFieldsLabelTranslation::getLabelFor($field);
// Check mandatory fields
if (
$field['mandatory'] == 1
&& (
$value === null
|| $value === ''
|| (($field['type'] === 'dropdown' || preg_match('/^dropdown-.+/i', $field['type'])) && $value == 0)
|| ($field['type'] === 'glpi_item' && $value === null)
|| (in_array($field['type'], ['date', 'datetime']) && $value == 'NULL')
)
) {
$empty_errors[] = $field['label'];
$valid = false;
} else if ($field['type'] == 'number' && !empty($value) && !is_numeric($value)) {
// Check number fields
$number_errors[] = $field['label'];
$valid = false;
} else if ($field['type'] == 'url' && !empty($value)) {
if (filter_var($value, FILTER_VALIDATE_URL) === false) {
$url_errors[] = $field['label'];
$valid = false;
}
}
}
if (!empty($empty_errors)) {
Session::AddMessageAfterRedirect(__("Some mandatory fields are empty", "fields") .
" : " . implode(', ', $empty_errors), false, ERROR);
}
if (!empty($number_errors)) {
Session::AddMessageAfterRedirect(__("Some numeric fields contains non numeric values", "fields") .
" : " . implode(', ', $number_errors), false, ERROR);
}
if (!empty($url_errors)) {
Session::AddMessageAfterRedirect(__("Some URL fields contains invalid links", "fields") .
" : " . implode(', ', $url_errors), false, ERROR);
}
return $valid;
}
public static function findContainer($itemtype, $type = 'tab', $subtype = '')
{
$condition = [
'is_active' => 1,
['type' => $type],
];
$entity = isset($_SESSION['glpiactiveentities'])
? $_SESSION['glpiactiveentities']
: 0;
$condition += getEntitiesRestrictCriteria("", "", $entity, true, true);
if ($subtype != '') {
if ($subtype == $itemtype . '$main') {
$condition[] = ['type' => 'dom'];
} else {
$condition[] = ['type' => ['!=', 'dom']];
$condition['subtype'] = $subtype;
}
}
$container = new PluginFieldsContainer();
$itemtypes = $container->find($condition);
$id = 0;
if (count($itemtypes) < 1) {
return false;
}
foreach ($itemtypes as $data) {
$dataitemtypes = json_decode($data['itemtypes']);
if (in_array($itemtype, $dataitemtypes) != false) {
$id = $data['id'];
}
}
//profiles restriction
if (isset($_SESSION['glpiactiveprofile']['id'])) {
$profile = new PluginFieldsProfile();
if (isset($id)) {
$found = $profile->find(['profiles_id' => $_SESSION['glpiactiveprofile']['id'],
'plugin_fields_containers_id' => $id
]);
$first_found = array_shift($found);
if ($first_found === null || $first_found['right'] == null || $first_found['right'] == 0) {
return false;
}
}
}
return $id;
}
/**
* Post item hook for add
* Do store data in db
*
* @param CommonDBTM $item Item instance
*
* @return CommonDBTM|true
*/
public static function postItemAdd(CommonDBTM $item)
{
if (property_exists($item, 'plugin_fields_data')) {
$data = $item->plugin_fields_data;
$data['items_id'] = $item->getID();
//update data
$container = new self();
if ($container->updateFieldsValues($data, $item->getType(), isset($_REQUEST['massiveaction']))) {
return true;
}
return $item->input = [];
}
}
/**
* Pre item hook for update
* Do store data in db
*
* @param CommonDBTM $item Item instance
*
* @return boolean
*/
public static function preItemUpdate(CommonDBTM $item)
{
self::preItem($item);
if (property_exists($item, 'plugin_fields_data')) {
$data = $item->plugin_fields_data;
//update data
$container = new self();
if (
count($data) == 0
|| $container->updateFieldsValues($data, $item->getType(), isset($_REQUEST['massiveaction']))
) {
return true;
}
return $item->input = [];
}
}
/**
* Pre item hook for add and update
* Validates and store plugin data in item object
*
* @param CommonDBTM $item Item instance
*
* @return boolean
*/
public static function preItem(CommonDBTM $item)
{
//find container (if not exist, do nothing)
if (isset($_REQUEST['c_id'])) {
$c_id = $_REQUEST['c_id'];
} else {
$type = 'dom';
if (isset($_REQUEST['_plugin_fields_type'])) {
$type = $_REQUEST['_plugin_fields_type'];
}
$subtype = '';
if ($type == 'domtab') {
$subtype = $_REQUEST['_plugin_fields_subtype'];
}
if (false === ($c_id = self::findContainer(get_Class($item), $type, $subtype))) {
// tries for 'tab'
if (false === ($c_id = self::findContainer(get_Class($item)))) {
return false;
}
}
}
//need to check if container is usable on this object entity
$loc_c = new PluginFieldsContainer();
$loc_c->getFromDB($c_id);
$entities = [$loc_c->fields['entities_id']];
if ($loc_c->fields['is_recursive']) {
$entities = getSonsOf(getTableForItemType('Entity'), $loc_c->fields['entities_id']);
}
//workaround: when a ticket is created from readdonly profile,
//it is not initialized; see https://github.com/glpi-project/glpi/issues/1438
if (!isset($item->fields) || count($item->fields) == 0) {
$item->fields = $item->input;
}
if ($item->isEntityAssign() && !in_array($item->getEntityID(), $entities)) {
return false;
}
if (false !== ($data = self::populateData($c_id, $item))) {
if (self::validateValues($data, $item::getType(), isset($_REQUEST['massiveaction'])) === false) {
return $item->input = [];
}
return $item->plugin_fields_data = $data;
}
return;
}
/**
* Populates fields data from item
*
* @param integer $c_id Container ID
* @param CommonDBTM $item Item instance
*
* @return array|false
*/
private static function populateData($c_id, CommonDBTM $item)
{
//find fields associated to found container
$field_obj = new PluginFieldsField();
$fields = $field_obj->find(
[
'plugin_fields_containers_id' => $c_id,
'type' => ['!=', 'header']
],
"ranking"
);
//prepare data to update
$data = ['plugin_fields_containers_id' => $c_id];
if (!$item->isNewItem()) {
//no ID yet while creating
$data['items_id'] = $item->getID();
}
// Add status so it can be used with status overrides
$status_field_name = PluginFieldsStatusOverride::getStatusFieldName($item->getType());
$data[$status_field_name] = null;
if (array_key_exists($status_field_name, $item->input) && $item->input[$status_field_name] !== '') {
$data[$status_field_name] = (int)$item->input[$status_field_name];
} elseif (array_key_exists($status_field_name, $item->fields) && $item->fields[$status_field_name] !== '') {
$data[$status_field_name] = (int)$item->fields[$status_field_name];
}
$has_fields = false;
foreach ($fields as $field) {
if ($field['type'] == 'glpi_item') {
$itemtype_key = sprintf('itemtype_%s', $field['name']);
$items_id_key = sprintf('items_id_%s', $field['name']);
if (!isset($item->input[$itemtype_key], $item->input[$items_id_key])) {
continue; // not a valid input
}
$has_fields = true;
$data[$itemtype_key] = $item->input[$itemtype_key];
$data[$items_id_key] = $item->input[$items_id_key];
continue; // bypass unique field handling
}
if (isset($item->input[$field['name']])) {
//standard field
$input = $field['name'];
} else {
//dropdown field
$input = "plugin_fields_" . $field['name'] . "dropdowns_id";
}
if (isset($item->input[$input])) {
$has_fields = true;
// Before is_number check, help user to have a number correct, during a massive action of a number field
if ($field['type'] == 'number') {
$item->input[$input] = str_replace(",", ".", $item->input[$input]);
}
$data[$input] = $item->input[$input];
}
}
if ($has_fields === true) {
return $data;
} else {
return false;
}
}
public static function getAddSearchOptions($itemtype, $containers_id = false)
{
global $DB;
$opt = [];
$i = 76665;
$search_string = json_encode($itemtype);
// Backslashes must be doubled in LIKE clause, according to MySQL documentation:
// > To search for \, specify it as \\\\; this is because the backslashes are stripped
// > once by the parser and again when the pattern match is made,
// > leaving a single backslash to be matched against.
$search_string = str_replace('\\', '\\\\', $search_string);
$query = "SELECT DISTINCT fields.id, fields.name, fields.label, fields.type, fields.is_readonly, fields.allowed_values,
containers.name as container_name, containers.label as container_label,
containers.itemtypes, containers.id as container_id, fields.id as field_id
FROM glpi_plugin_fields_containers containers
INNER JOIN glpi_plugin_fields_profiles profiles
ON containers.id = profiles.plugin_fields_containers_id
AND profiles.right > 0
AND profiles.profiles_id = " . (int) $_SESSION['glpiactiveprofile']['id'] . "
INNER JOIN glpi_plugin_fields_fields fields
ON containers.id = fields.plugin_fields_containers_id
AND containers.is_active = 1
WHERE containers.itemtypes LIKE '%" . $DB->escape($search_string) . "%'
AND fields.type != 'header'
ORDER BY fields.id ASC";
$res = $DB->query($query);
while ($data = $DB->fetchAssoc($res)) {
if ($containers_id !== false) {
// Filter by container (don't filter by SQL for have $i value with few containers for a itemtype)
if ($data['container_id'] != $containers_id) {
$i++;
continue;
}
}
$tablename = getTableForItemType(self::getClassname($itemtype, $data['container_name']));
//get translations
$container = [
'itemtype' => PluginFieldsContainer::getType(),
'id' => $data['container_id'],
'label' => $data['container_label']
];
$data['container_label'] = PluginFieldsLabelTranslation::getLabelFor($container);
$field = [
'itemtype' => PluginFieldsField::getType(),
'id' => $data['field_id'],
'label' => $data['label']
];
$data['label'] = PluginFieldsLabelTranslation::getLabelFor($field);
// Default SO params
$opt[$i]['table'] = $tablename;
$opt[$i]['field'] = $data['name'];
$opt[$i]['name'] = $data['container_label'] . " - " . $data['label'];
$opt[$i]['linkfield'] = $data['name'];
$opt[$i]['joinparams']['jointype'] = "itemtype_item";
$opt[$i]['pfields_type'] = $data['type'];
if ($data['is_readonly']) {
$opt[$i]['massiveaction'] = false;
}
switch ($data['type']) {
case 'yesno':
$opt[$i]['datatype'] = "bool";
break;
case 'textarea':
case 'number':
$opt[$i]['datatype'] = "text";
break;
case 'date':
case 'datetime':
$opt[$i]['datatype'] = $data['type'];
break;
case 'url':
$opt[$i]['datatype'] = 'weblink';
break;
default:
$opt[$i]['datatype'] = "string";
}
$dropdown_matches = [];
if ($data['type'] === "dropdown") {
$opt[$i]['table'] = 'glpi_plugin_fields_' . $data['name'] . 'dropdowns';
$opt[$i]['field'] = 'completename';
$opt[$i]['linkfield'] = "plugin_fields_" . $data['name'] . "dropdowns_id";
$opt[$i]['datatype'] = "dropdown";
$opt[$i]['forcegroupby'] = true;
$opt[$i]['joinparams']['jointype'] = "";
$opt[$i]['joinparams']['beforejoin']['table'] = $tablename;
$opt[$i]['joinparams']['beforejoin']['joinparams']['jointype'] = "itemtype_item";
} elseif (
preg_match('/^dropdown-(?<class>.+)$/i', $data['type'], $dropdown_matches)
&& class_exists($dropdown_matches['class'])
) {
$opt[$i]['table'] = CommonDBTM::getTable($dropdown_matches['class']);
$opt[$i]['field'] = 'name';
$opt[$i]['linkfield'] = $data['name'];
$opt[$i]['right'] = 'all';
$opt[$i]['datatype'] = "dropdown";
$opt[$i]['forcegroupby'] = true;
$opt[$i]['joinparams']['jointype'] = "";
$opt[$i]['joinparams']['beforejoin']['table'] = $tablename;
$opt[$i]['joinparams']['beforejoin']['joinparams']['jointype'] = "itemtype_item";
} elseif ($data['type'] === "glpi_item") {
$itemtype_field = sprintf('itemtype_%s', $data['name']);
$items_id_field = sprintf('items_id_%s', $data['name']);
$opt[$i]['table'] = $tablename;
$opt[$i]['field'] = $itemtype_field;
$opt[$i]['linkfield'] = $itemtype_field;
$opt[$i]['name'] = $data['container_label'] . " - " . $data['label'] . ' - ' . _n('Associated item type', 'Associated item types', Session::getPluralNumber());
$opt[$i]['datatype'] = 'itemtypename';
$opt[$i]['types'] = !empty($data['allowed_values']) ? json_decode($data['allowed_values']) : [];
$opt[$i]['additionalfields'] = ['itemtype'];
$opt[$i]['joinparams']['jointype'] = 'itemtype_item';
$opt[$i]['forcegroupby'] = true;
$opt[$i]['massiveaction'] = false;
$i++;
$opt[$i]['table'] = $tablename;
$opt[$i]['field'] = $items_id_field;
$opt[$i]['linkfield'] = $items_id_field;
$opt[$i]['name'] = $data['container_label'] . " - " . $data['label'] . ' - ' . __('Associated item ID');
$opt[$i]['massiveaction'] = false;
$opt[$i]['joinparams']['jointype'] = 'itemtype_item';
$opt[$i]['datatype'] = 'text';
$opt[$i]['additionalfields'] = ['itemtype'];
}
$i++;
}
return $opt;
}
/**
* Get subtypes for specified itemtype.
* Was previously retrieved using $item::defineTabs() but
* this is not relevant with actual core.
*
* @param CommonDBTM $item Item instance
*
* @return array
*/
private static function getSubtypes($item)
{
$tabs = [];
switch ($item::getType()) {
case Ticket::getType():
case Problem::getType():
$tabs = [
$item::getType() . '$2' => __('Solution')
];
break;
case Change::getType():
$tabs = [
'Change$1' => __('Analysis'),
'Change$2' => __('Solution'),
'Change$3' => __('Plans')
];
break;
case Entity::getType():
$tabs = [
'Entity$2' => __('Address'),
'Entity$3' => __('Advanced information'),
'Entity$4' => __('Notifications'),
'Entity$5' => __('Assistance'),
'Entity$6' => __('Assets')
];
break;
default:
//Toolbox::logDebug('Item type ' . $item::getType() . ' does not have any preconfigured subtypes!');
/* For debug purposes
$tabs = $item->defineTabs();
list($id, ) = each($tabs);
// delete first element of array ($main)
unset($tabs[$id]);*/
break;
}
return $tabs;
}
/**
* Retrieve the class name corresponding to an itemtype for given container.
*
* @param string $itemtype Name of associated itemtype
* @param string $container_name Name of container
* @param string $suffix Suffix to add
*
* @return string
*/
public static function getClassname(string $itemtype, string $container_name, string $suffix = ''): string
{
return sprintf(
'PluginFields%s%s',
ucfirst(self::getSystemName($itemtype, $container_name)),
$suffix
);
}
/**
* Retrieve the system name corresponding to an itemtype for given container.
*
* @param string $itemtype Name of associated itemtype
* @param string $container_name Name of container
*
* @return string
*/
protected static function getSystemName(string $itemtype, string $container_name): string
{
return strtolower(str_replace('\\', '', $itemtype) . preg_replace('/s$/', '', $container_name));
}
public static function getIcon()
{
return "fas fa-tasks";
}
public static function getNameField()
{
return 'label';
}
public function prepareInputForClone($input)
{
if (array_key_exists('itemtypes', $input) && !empty($input['itemtypes'])) {
// $input has been transformed with `Toolbox::addslashes_deep()`, and `self::prepareInputForAdd()`
// is expecting an array, so it have to be unslashed then json decoded.
$input['itemtypes'] = json_decode(Sanitizer::dbUnescape($input['itemtypes']));
} else {
unset($input['itemtypes']);
}
return $input;
}
public function getCloneRelations(): array
{
return [
PluginFieldsContainerDisplayCondition::class,
PluginFieldsField::class,
PluginFieldsLabelTranslation::class,
PluginFieldsProfile::class,
];
}
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists