. * ------------------------------------------------------------------------- * @copyright Copyright (C) 2009-2022 by GenericObject plugin team. * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html * @link https://github.com/pluginsGLPI/genericobject * ------------------------------------------------------------------------- */ class PluginGenericobjectField extends CommonDBTM { /** * * Displat all fields present in DB for an itemtype * @param $id the itemtype's id */ public static function showObjectFieldsForm($id) { global $DB, $GO_BLACKLIST_FIELDS, $GO_READONLY_FIELDS, $GO_FIELDS, $CFG_GLPI; $url = Toolbox::getItemTypeFormURL(__CLASS__); $object_type = new PluginGenericobjectType(); $object_type->getFromDB($id); $itemtype = $object_type->fields['itemtype']; $fields_in_db = PluginGenericobjectSingletonObjectField::getInstance($itemtype); $used_fields = []; //Reset fields definition only to keep the itemtype ones $GO_FIELDS = []; plugin_genericobject_includeCommonFields(true); PluginGenericobjectType::includeLocales($object_type->fields['name']); PluginGenericobjectType::includeConstants($object_type->fields['name'], true); self::addReadOnlyFields($object_type); foreach ($GO_BLACKLIST_FIELDS as $autofield) { if (!in_array($autofield, $used_fields)) { $used_fields[$autofield] = $autofield; } } echo "
"; echo "
"; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; $total = count($fields_in_db); $global_index = $index = 1; $haveCheckbox = false; foreach ($fields_in_db as $field => $value) { $readonly = in_array($field, $GO_READONLY_FIELDS); $blacklist = in_array($field, $GO_BLACKLIST_FIELDS); self::displayFieldDefinition($url, $itemtype, $field, $index, ($global_index==$total)); //All backlisted fields cannot be moved, and are listed first if (!$readonly) { $index++; } if (!$blacklist && !$readonly) { $haveCheckbox = true; } //$table = getTableNameForForeignKeyField($field); $used_fields[$field] = $field; $global_index++; } echo "
"; echo __("Fields associated with the object", "genericobject") . " : "; echo $itemtype::getTypeName(); echo "
" . __("Label", "genericobject") . "" . __("Name in DB", "genericobject") . "
"; if ($haveCheckbox) { echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo "
"; echo "".__('Check all')."/"; echo "".__('Uncheck all').""; echo Html::submit(__("Delete permanently"), [ 'name' => 'delete', ]); echo "
"; } $dropdownFields = self::dropdownFields("new_field", $itemtype, $used_fields); if ($dropdownFields) { echo "
"; echo ""; echo ""; echo ""; echo ""; echo ""; echo "
" . __("Add new field", "genericobject") . ""; echo ""; echo "
"; } Html::closeForm(); echo "
"; } /** * Method to set fields as read only, when the depend on some features * that are enabled * @since 0.85+2.4.0 */ static function addReadOnlyFields(PluginGenericobjectType $type) { global $GO_READONLY_FIELDS; if ($type->canBeReserved()) { $GO_READONLY_FIELDS[] = 'users_id'; $GO_READONLY_FIELDS[] = 'locations_id'; } if ($type->canUseGlobalSearch()) { $GO_READONLY_FIELDS[] = 'serial'; $GO_READONLY_FIELDS[] = 'otherserial'; $GO_READONLY_FIELDS[] = 'locations_id'; $GO_READONLY_FIELDS[] = 'states_id'; $GO_READONLY_FIELDS[] = 'users_id'; $GO_READONLY_FIELDS[] = 'groups_id'; $GO_READONLY_FIELDS[] = 'manufacturers_id'; $GO_READONLY_FIELDS[] = 'users_id_tech'; } if ($type->canUseItemDevice()) { $GO_READONLY_FIELDS[] = 'locations_id'; } } /** * Get the name of the field, as defined in a constant file * The name may be the same, or not depending if it's an isolated dropdown or not */ static function getFieldName($field, $itemtype, $options, $remove_prefix = false) { global $DB; $field_orig = $field; $field_table = null; $input_type = isset($options['input_type']) ? $options['input_type'] : null; switch ($input_type) { case 'dropdown': $dropdown_type = isset($options['dropdown_type']) ? $options['dropdown_type'] : null; $fk = getForeignKeyFieldForTable(getTableForItemType($itemtype)); if ($dropdown_type == 'isolated') { if (!$remove_prefix) { $field = preg_replace("/s_id$/", $field, $fk); } else { $fk = preg_replace("/s_id$/", "", $fk); $field = preg_replace("/".$fk."/", "", $field); } } $field_table = getTableNameForForeignKeyField($field); //Prepend plugin's table prefix if this dropdown is not already handled by GLPI natively if (substr($field, 0, strlen('plugin_genericobject')) !== 'plugin_genericobject' and ( substr($field_table, strlen('glpi_')) === substr($field, 0, strlen($field) -strlen('_id')) ) and !$DB->tableExists($field_table) ) { if (!$remove_prefix) { $field = 'plugin_genericobject_' . $field;} } break; } return $field; } /** * * Display a dropdown with all available fields for an itemtype * @since * @param $name the dropdown name * @param $itemtype the itemtype * @param $used an array which contains all fields already added * * @return the dropdown random ID */ static function dropdownFields($name, $itemtype, $used = []) { global $GO_FIELDS; $dropdown_types = []; foreach ($GO_FIELDS as $field => $values) { $message = ""; $field_options = []; $field = self::getFieldName($field, $itemtype, $values, false); if (!in_array($field, $used)) { if (!isset($dropdown_types[$field])) { //Global management : //meaning that a dropdown can be useful in all types (for example type, model, etc.) if (isset($values['input_type']) && $values['input_type'] == 'dropdown') { if (isset($values['entities_id'])) { $field_options[] = __("Entity")." : ".Dropdown::getYesNo($values['entities_id']); if ($values['entities_id']) { if (isset($values['is_recursive'])) { $field_options[] = __("Child entities")." : ".Dropdown::getYesNo($values['is_recursive']); } } } else { $field_options[] = __("Entity")." : ".Dropdown::getYesNo(0); } if (isset($values['is_tree'])) { $field_options[] = __("tree structure")." : ".Dropdown::getYesNo($values['is_tree']); } else { $field_options[] = __("tree structure")." : ".Dropdown::getYesNo(0); } //if (isset($values['isolated']) and $values['isolated']) { // $field_options[] = __("Isolated") . " : ". Dropdown::getYesNo($values['isolated']); //} else { // $field_options[] = __("Isolated") . " : ". Dropdown::getYesNo(0); //} } if (!empty($field_options)) { $message = "(".trim( implode(", ", $field_options)).")"; } } $dropdown_types[$field] = $values['name']." ".$message; } } // Don't show dropdown empty if (empty($dropdown_types)) { return ''; } ksort($dropdown_types); return Dropdown::showFromArray($name, $dropdown_types, ['display' => false]); } /** * * Get field's options defined in constant files. * If this field has not been defined, it means that this field has been defined globally and * must be dynamically created. * * @param $field the current field * @param $itemtype the itemtype * @return an array which contains the full field definition */ static function getFieldOptions($field, $itemtype = "") { global $GO_FIELDS; $options = []; $cleaned_field = preg_replace("/^plugin_genericobject_/", '', $field); if (!isset($GO_FIELDS[$cleaned_field]) && !empty($itemtype)) { // This field has been dynamically defined because it's an isolated dropdown $tmpfield = self::getFieldName( $field, $itemtype, [ 'dropdown_type' => 'isolated', 'input_type' => 'dropdown' ], true ); $options = $GO_FIELDS[$tmpfield]; $options['realname'] = $tmpfield; } else if (isset($GO_FIELDS[$cleaned_field])) { $options = $GO_FIELDS[$cleaned_field]; $options['realname'] = $cleaned_field; } return $options; } public static function displayFieldDefinition($target, $itemtype, $field, $index, $last = false) { global $GO_FIELDS, $CFG_GLPI, $GO_BLACKLIST_FIELDS, $GO_READONLY_FIELDS; $readonly = in_array($field, $GO_READONLY_FIELDS); $blacklist = in_array($field, $GO_BLACKLIST_FIELDS); $options = self::getFieldOptions($field, $itemtype); echo ""; echo ""; if (!$blacklist && !$readonly) { echo ""; } else { echo ""; } echo ""; echo "" . __($options['name'], 'genericobject') . ""; echo "" . $field . ""; echo ""; if ((!$blacklist || $readonly) && $index > 1) { Html::showSimpleForm($target, $CFG_GLPI["root_doc"] . "/pics/deplier_up.png", 'up', ['field' => $field, 'action' => 'up', 'itemtype' => $itemtype], $CFG_GLPI["root_doc"] . "/pics/deplier_up.png"); } echo ""; echo ""; if ((!$blacklist || $readonly) && !$last) { Html::showSimpleForm($target, $CFG_GLPI["root_doc"] . "/pics/deplier_down.png", 'down', ['field' => $field, 'action' => 'down', 'itemtype' => $itemtype], $CFG_GLPI["root_doc"] . "/pics/deplier_down.png"); } echo ""; echo ""; } /** * Add a new field in DB * @param table the table * @param field the field to delete * @return nothing */ public static function addNewField($table, $field, $after = false) { global $DB; _log("add", $field, "from", $table); $itemtype = getItemTypeForTable($table); if (!$DB->fieldExists($table, $field, false)) { $options = self::getFieldOptions($field, $itemtype); $query = "ALTER TABLE `$table` ADD `$field` "; switch ($options['input_type']) { case 'dropdown_yesno' : case 'dropdown_global' : case 'bool' : $query .= "TINYINT (1) NOT NULL DEFAULT '0'"; break; case 'emptyspace' : case 'text' : $query .= "VARCHAR ( 255 ) collate utf8_unicode_ci NOT NULL DEFAULT ''"; break; case 'multitext' : $query .= "TEXT NULL"; break; case 'dropdown' : case 'integer' : $query .= "INT ( 11 ) NOT NULL DEFAULT '0'"; break; case 'date': $query.="DATE DEFAULT NULL"; break; case 'datetime': $query.="TIMESTAMP NULL DEFAULT NULL"; break; case 'float' : $query .= "FLOAT NOT NULL DEFAULT '0'"; break; case 'decimal' : $query .= "DECIMAL(20,4) NOT NULL DEFAULT '0.0000'"; break; } if ($after) { $query.=" AFTER `$after`"; } $DB->query($query); //Reload list of fields for this itemtype in the singleton $recursive = $entity_assign = $tree = false; $table = getTableNameForForeignKeyField($field); if ($table != '' && !$DB->tableExists($table)) { //Cannot use standard methods because class doesn't exists yet ! $name = str_replace("glpi_plugin_genericobject_", "", $table); $name = getSingular($name); $options['linked_itemtype'] = $itemtype; PluginGenericobjectType::addNewDropdown( $name, 'PluginGenericobject'.ucfirst($name), $options ); } // Invalidate menu data in current session unset($_SESSION['glpimenu']); PluginGenericobjectSingletonObjectField::getInstance($itemtype, true); } } /** * Delete a field in DB * @param table the table * @param field the field to delete * @return nothing */ static function deleteField($table, $field) { global $DB; //Remove field from displaypreferences self::deleteDisplayPreferences($table, $field); //If field exists, drop it ! if ($DB->fieldExists($table, $field)) { $DB->query("ALTER TABLE `$table` DROP `$field`"); } $table = getTableNameForForeignKeyField($field); //If dropdown is managed by the plugin if ($table != '' && preg_match('/plugin_genericobject_(.*)/', $table, $results)) { //Delete dropdown table $query = "DROP TABLE `$table`"; $DB->query($query); //Delete dropdown files & class $name = getSingular($results[1]); PluginGenericobjectType::deleteClassFile($name); PluginGenericobjectType::deleteFormFile($name); PluginGenericobjectType::deletesearchFile($name); } } static function deleteDisplayPreferences($table, $field) { $pref = new DisplayPreference(); $itemtype = getItemTypeForTable($table); $searchopt = Search::getCleanedOptions($itemtype); foreach ($searchopt as $num => $option) { if ((isset($option['field']) && ($option['field'] == $field)) || (isset($option['field']) && $option['linkfield'] == $field)) { $pref->deleteByCriteria([ 'itemtype' => $itemtype, 'num' => $num ]); break; } } } /** * Change field order in DB * @params an array which contains the itemtype, the field to move and the action (up/down) * @return nothing */ static function changeFieldOrder($params = []) { global $DB; $itemtype = $params['itemtype']; $field = $params['field']; $table = getTableForItemType($itemtype); $fields = PluginGenericobjectSingletonObjectField::getInstance($params['itemtype']); //If action is down, reverse array first if ($params['action'] == 'down') { $fields = array_reverse($fields); } //Get array keys $keys = array_keys($fields); //Index represents current position of $field $index = 0; foreach ($keys as $id => $key) { if ($key == $field) { $index = $id; } } //Get 2 positions before and move field if ($params['action'] == 'down') { $previous = $index - 1; } else { $previous = $index - 2; } if (isset($keys[$previous])) { $parent = $fields[$keys[$previous]]; $query = "ALTER TABLE `$table` MODIFY `$field` ".$fields[$field]['Type']; $query .= " AFTER `".$fields[$keys[$previous]]['Field']."`"; $DB->query($query) or die ($DB->error()); } } public static function checkNecessaryFieldsDelete($itemtype, $field) { $type = new PluginGenericobjectType(); $type->getFromDBByType($itemtype); if ($type->canUseNetworkPorts() && 'locations_id' == $field) { return false; } /* if ($type->fields['use_direct_connections']) { foreach(['users_id','groups_id',' states_id','locations_id'] as $tmp_field) { if ($tmp_field == $field) { return false; } } }*/ return true; } static function install(Migration $migration) { } static function uninstall() { } }