diff --git a/ajax/container_display_condition.php b/ajax/container_display_condition.php
new file mode 100644
index 00000000..d5d3853e
--- /dev/null
+++ b/ajax/container_display_condition.php
@@ -0,0 +1,61 @@
+.
+ * -------------------------------------------------------------------------
+ * @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
+ * -------------------------------------------------------------------------
+ */
+
+include ("../../../inc/includes.php");
+
+if (isset($_GET['action'])) {
+ if ($_GET['action'] === 'get_add_form') {
+ $status_override = new PluginFieldsContainerDisplayCondition();
+ $status_override->showForm(0, $_GET);
+ } else if ($_GET['action'] === 'get_edit_form') {
+ $status_override = new PluginFieldsContainerDisplayCondition();
+ $status_override->getFromDB($_GET['id']);
+ $status_override->showForm($_GET['id'], $_GET);
+ }
+
+} else if (isset($_POST['action'])) {
+ if($_POST['action'] === 'get_itemtype_so') {
+ if(isset($_POST['itemtype']) && class_exists($_POST['itemtype'])) {
+ echo PluginFieldsContainerDisplayCondition::showItemtypeFieldForm($_POST['itemtype']) ;
+ } else {
+ echo "";
+ }
+ } else if($_POST['action'] === 'get_condition_switch_so') {
+ if(isset($_POST['search_option_id']) && (isset($_POST['itemtype']) && class_exists($_POST['itemtype']))) {
+ echo PluginFieldsContainerDisplayCondition::showSearchOptionCondition($_POST['search_option_id'], $_POST['itemtype']);
+ } else {
+ echo "";
+ }
+
+ }
+} else {
+ http_response_code(400);
+ die();
+}
diff --git a/front/containerdisplaycondition.form.php b/front/containerdisplaycondition.form.php
new file mode 100644
index 00000000..e46ac683
--- /dev/null
+++ b/front/containerdisplaycondition.form.php
@@ -0,0 +1,49 @@
+.
+ * -------------------------------------------------------------------------
+ * @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
+ * -------------------------------------------------------------------------
+ */
+
+include ("../../../inc/includes.php");
+
+$status_override = new PluginFieldsContainerDisplayCondition();
+if (isset($_POST["add"])) {
+ $status_override->check(-1, CREATE, $_POST);
+ $status_override->add($_POST);
+ Html::back();
+} else if (isset($_POST["update"])) {
+ $status_override->check(-1, UPDATE);
+ $status_override->update($_POST);
+ Html::back();
+} else if (isset($_POST["delete"])) {
+ $status_override->check($_POST['id'], PURGE);
+ $status_override->delete([
+ 'id' => $_POST['id']
+ ]);
+ Html::back();
+}
+Html::back();
diff --git a/hook.php b/hook.php
index 7146aeb4..ce35ddf9 100644
--- a/hook.php
+++ b/hook.php
@@ -58,7 +58,8 @@ function plugin_fields_install() {
'PluginFieldsValue',
'PluginFieldsProfile',
'PluginFieldsMigration',
- 'PluginFieldsStatusOverride'
+ 'PluginFieldsStatusOverride',
+ 'PluginFieldsContainerDisplayCondition',
];
$migration = new Migration($version);
@@ -131,7 +132,8 @@ function plugin_fields_uninstall() {
'PluginFieldsField',
'PluginFieldsValue',
'PluginFieldsProfile',
- 'PluginFieldsMigration'
+ 'PluginFieldsMigration',
+ 'PluginFieldsContainerDisplayCondition'
];
foreach ($classesToUninstall as $class) {
diff --git a/inc/container.class.php b/inc/container.class.php
index 95424b60..90cda1e1 100644
--- a/inc/container.class.php
+++ b/inc/container.class.php
@@ -403,6 +403,7 @@ function defineTabs($options = []) {
$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;
@@ -564,6 +565,12 @@ function pre_deleteItem() {
'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([
@@ -1033,7 +1040,11 @@ function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
}
if (!$item->isEntityAssign() || in_array($item->fields['entities_id'], $entities)) {
- $tabs_entries[$tab_name] = $tab_label;
+
+ $display_condition = new PluginFieldsContainerDisplayCondition();
+ if($display_condition->computeDisplayContainer($item, $data['id'])) {
+ $tabs_entries[$tab_name] = $tab_label;
+ }
}
}
}
diff --git a/inc/containerdisplaycondition.class.php b/inc/containerdisplaycondition.class.php
new file mode 100644
index 00000000..d8342949
--- /dev/null
+++ b/inc/containerdisplaycondition.class.php
@@ -0,0 +1,478 @@
+.
+ * -------------------------------------------------------------------------
+ * @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\Application\View\TemplateRenderer;
+use Glpi\Toolbox\Sanitizer;
+
+class PluginFieldsContainerDisplayCondition extends CommonDBTM {
+ static $rightname = 'config';
+
+ const SHOW_CONDITION_EQ = 1;
+ const SHOW_CONDITION_NE = 2;
+ const SHOW_CONDITION_LT = 3;
+ const SHOW_CONDITION_GT = 4;
+ const SHOW_CONDITION_REGEX = 5;
+
+ static function canCreate() {
+ return self::canUpdate();
+ }
+
+ static function canPurge() {
+ return self::canUpdate();
+ }
+
+ 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,
+ `plugin_fields_containers_id` INT {$default_key_sign} NOT NULL DEFAULT '0',
+ `itemtype` VARCHAR(100) DEFAULT NULL,
+ `search_option` VARCHAR(255) DEFAULT NULL,
+ `condition` VARCHAR(255) DEFAULT NULL,
+ `value` VARCHAR(255) DEFAULT NULL,
+ `is_visible` TINYINT NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `plugin_fields_containers_id_itemtype` (`plugin_fields_containers_id`, `itemtype`)
+ ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;";
+ $DB->query($query) or die ($DB->error());
+ }
+
+ return true;
+ }
+
+ public static function getEnumCondition($is_dropdown = false) : array {
+
+ if ($is_dropdown){
+ return [
+ self::SHOW_CONDITION_EQ => '=',
+ self::SHOW_CONDITION_NE => '≠'
+ ];
+ } else {
+ return [
+ self::SHOW_CONDITION_EQ => '=',
+ self::SHOW_CONDITION_NE => '≠',
+ self::SHOW_CONDITION_LT => '<',
+ self::SHOW_CONDITION_GT => '>',
+ self::SHOW_CONDITION_REGEX => __('regular expression matches', 'fields'),
+ ];
+ }
+
+ }
+
+ public static function getConditionName($condition) {
+ switch ($condition) {
+ case self::SHOW_CONDITION_EQ:
+ echo '=';
+ break;
+ case self::SHOW_CONDITION_NE:
+ echo '≠';
+ break;
+ case self::SHOW_CONDITION_LT:
+ echo '<';
+ break;
+ case self::SHOW_CONDITION_GT:
+ echo '>';
+ case self::SHOW_CONDITION_REGEX:
+ echo __('regular expression matches', 'fields');
+ break;
+ }
+ }
+
+
+ static function uninstall() {
+ global $DB;
+ $DB->query("DROP TABLE IF EXISTS `".self::getTable()."`");
+ return true;
+ }
+
+
+ static function getTypeName($nb = 0) {
+ return __('Condition to hide block', 'fields');
+ }
+
+
+ function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
+ return self::createTabEntry(self::getTypeName(), countElementsInTable(self::getTable(),
+ ['plugin_fields_containers_id' => $item->getID()]));
+ }
+
+
+ static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {
+ if ($item instanceof PluginFieldsContainer) {
+ self::showForTabContainer($item);
+ return true;
+ }
+ return false;
+ }
+
+
+ public static function getDisplayConditionForContainer(int $container_id): array {
+ global $DB;
+ $iterator = $DB->request([
+ 'SELECT' => [
+ self::getTable().'.*',
+ ],
+ 'FROM' => self::getTable(),
+ 'WHERE' => [
+ 'plugin_fields_containers_id' => $container_id,
+ ]
+ ]);
+
+ $conditions = [];
+ foreach ($iterator as $data) {
+ $conditions[] = $data;
+ }
+ return $conditions;
+ }
+
+
+ private static function getItemtypesForContainer(int $container_id): array {
+ global $DB;
+
+ $iterator = $DB->request([
+ 'SELECT' => ['itemtypes'],
+ 'FROM' => PluginFieldsContainer::getTable(),
+ 'WHERE' => [
+ 'id' => $container_id,
+ ]
+ ]);
+
+ if (count($iterator)) {
+ $itemtypes = $iterator->current()['itemtypes'];
+ $itemtypes = importArrayFromDB($itemtypes);
+ foreach ($itemtypes as $itemtype) {
+ $results[$itemtype] = $itemtype::getTypeName();
+ }
+ return $results;
+ }
+ return [];
+ }
+
+
+ public static function getFieldName($so_id, $itemtype) {
+ echo Search::getOptions($itemtype)[$so_id]['name'];
+ }
+
+
+ public static function showItemtypeFieldForm($itemtype) {
+
+ $rand = mt_rand();
+ $out = "";
+ $out .= Dropdown::showFromArray("search_option",self::removeBlackListedOption(Search::getOptions($itemtype), $itemtype),["display_emptychoice" => true, "display" => false, 'rand' => $rand]);
+
+ $out .= Ajax::updateItemOnSelectEvent(
+ "dropdown_search_option" . $rand,
+ "results_condition",
+ Plugin::getWebDir('fields') . '/ajax/container_display_condition.php',
+ [
+ 'search_option_id' => '__VALUE__',
+ 'itemtype' => $itemtype,
+ 'action' => 'get_condition_switch_so'
+ ]
+ );
+
+ echo $out;
+
+ }
+
+
+ public static function showSearchOptionCondition($searchoption_id, $itemtype, ?string $condition = null, ?string $value = null) {
+ $so = Search::getOptions($itemtype)[$searchoption_id];
+
+ $itemtypetable = $itemtype::getTable();
+
+ $twig_params = [
+ 'rand' => rand(),
+ 'is_dropdown' => false,
+ 'is_specific' => false,
+ 'is_list_values' => false,
+ 'condition' => $value,
+ 'value' => $value,
+ ];
+
+ if ($so['datatype'] == 'dropdown' || ($so['datatype'] == 'itemlink' && $so['table'] !== $itemtypetable)) {
+ $twig_params['is_dropdown'] = true;
+ $twig_params['dropdown_itemtype'] = getItemTypeForTable($so['table']);
+ $twig_params['list_conditions'] = self::getEnumCondition(true);
+ } elseif ($so['datatype'] == 'specific' && get_parent_class($itemtype) == CommonITILObject::getType()) {
+ $twig_params['list_conditions'] = self::getEnumCondition(true);
+ $twig_params['is_specific'] = true;
+ switch ($so['field']) {
+ case 'status':
+ $twig_params['is_list_values'] = true;
+ $twig_params['list_values'] = $itemtype::getAllStatusArray(false);
+ break;
+ case 'type':
+ $twig_params['is_list_values'] = true;
+ $twig_params['list_values'] = $itemtype::getTypes();
+ break;
+ case 'impact':
+ case 'urgency':
+ case 'priority':
+ $twig_params['item'] = new $itemtype();
+ $twig_params['itemtype_field'] = $so['field'];
+ break;
+ case 'global_validation':
+ $twig_params['is_list_values'] = true;
+ $twig_params['list_values'] = CommonITILValidation::getAllStatusArray(false, true);
+ break;
+ }
+ } else {
+ $twig_params['list_conditions'] = self::getEnumCondition(false);
+ }
+
+ TemplateRenderer::getInstance()->display('@fields/forms/container_display_condition_so_condition.html.twig', $twig_params);
+ }
+
+
+ public static function getRawValue($searchoption_id, $itemtype, $value) {
+
+ $so = Search::getOptions($itemtype)[$searchoption_id];
+ $itemtypetable = $itemtype::getTable();
+
+ $raw_value = '';
+
+ if ($so['datatype'] == 'dropdown' || ($so['datatype'] == 'itemlink' && $so['table'] !== $itemtypetable)) {
+ $dropdown_itemtype = getItemTypeForTable($so['table']);
+ $dropdown = new $dropdown_itemtype();
+ $dropdown->getFromDB($value);
+ $raw_value = $dropdown->fields['name'];
+ } else if ($so['datatype'] == 'specific' && get_parent_class($itemtype) == CommonITILObject::getType()) {
+ switch ($so['field']) {
+ case 'status':
+ $raw_value = $itemtype::getStatus($value);
+ break;
+ case 'impact':
+ $raw_value = $itemtype::getImpactName($value);
+ break;
+ case 'type':
+ $raw_value = $itemtype::getTicketTypeName($value);
+ break;
+ case 'urgency':
+ $raw_value = $itemtype::getUrgencyName($value);
+ break;
+ case 'priority':
+ $raw_value = $itemtype::getPriorityName($value);
+ break;
+ case 'global_validation':
+ $raw_value = CommonITILValidation::getStatus($value);
+ break;
+ }
+ }else{
+ $raw_value = $value;
+ }
+
+ echo $raw_value;
+ }
+
+
+ public static function removeBlackListedOption($array, $itemtype_class){
+
+ $itemtype_object = new $itemtype_class();
+ $allowed_so = [];
+
+ //remove "Common"
+ unset($array['common']);
+
+ $allowed_table = [getTableForItemType($itemtype_class), getTableForItemType(User::getType()), getTableForItemType(Group::getType())];
+
+ //use relation.constant.php to allow some tables (exclude Location which is managed later)
+ foreach (getDbRelations() as $tablename => $relation) {
+ foreach ($relation as $main_table => $foreignKey) {
+ if($main_table == getTableForItemType($itemtype_class)
+ && !is_array($foreignKey)
+ && getTableNameForForeignKeyField($foreignKey) != getTableForItemType(Location::getType())) {
+ $allowed_table[] = getTableNameForForeignKeyField($foreignKey);
+ }
+ }
+ }
+
+ if($itemtype_object->isEntityAssign()){
+ $allowed_table[] = getTableForItemType(Entity::getType());
+ }
+
+ //allew specific datatype
+ $allowed_datatype = ["email", "weblink", "specific", "itemlink", "string", "text","number", "dropdown", "decimal", "integer", "bool"];
+
+ foreach($array as $subKey => $subArray){
+ if(isset($subArray["table"]) && in_array($subArray["table"], $allowed_table)
+ && (isset($subArray["datatype"]) && in_array($subArray["datatype"], $allowed_datatype))
+ && !isset($subArray["nosearch"]) //Exclude SO with no search
+ && !isset($subArray["usehaving"]) //Exclude count SO ex: Ticket -> Number of sons tickets
+ && !isset($subArray["forcegroupby"]) //Exclude 1-n relation ex: Ticket_User
+ && !isset($subArray["computation"])){ //Exclude SO with computation Ex : Ticket -> Time to own exceeded
+ $allowed_so[$subKey] = $subArray["name"];
+ }
+ }
+
+ if($itemtype_object->maybeLocated()){
+ $allowed_so[80] = Location::getTypeName(0);
+ }
+
+ return $allowed_so;
+ }
+
+
+ public function computeDisplayContainer($item, $container_id){
+ //load all condition for itemtype and container
+ $displayCondition = new self();
+ $found_dc = $displayCondition->find(['itemtype' => get_class($item), 'plugin_fields_containers_id' => $container_id]);
+
+ if (count($found_dc)){
+ $display = true;
+ foreach ($found_dc as $data) {
+
+ $displayCondition->getFromDB($data['id']);
+ $result = $displayCondition->checkCondition($item);
+ if(!$result){
+ return $result;
+ }
+ }
+
+ return $display;
+ }else {
+ //no condition found -> display container
+ return true;
+ }
+ }
+
+
+ public function checkCondition($item){
+ $valueToCheck = $this->fields['value'];
+ $condition = $this->fields['condition'];
+ $searchOption = Search::getOptions(get_class($item))[$this->fields['search_option']];
+
+ $value = null;
+ switch ($searchOption['datatype']) {
+ case 'dropdown':
+ case 'email':
+ case 'weblink':
+ case 'itemlink':
+ case 'string':
+ case 'text':
+ case 'number':
+ case 'decimal':
+ case 'integer':
+ case 'bool':
+ $value = $valueToCheck;
+ break;
+ }
+
+ if($value !== null){
+ switch ($condition) {
+ case self::SHOW_CONDITION_EQ:
+ // '='
+ if ($value == $item->fields[$searchOption['linkfield']]){
+ return false;
+ }
+ break;
+ case self::SHOW_CONDITION_NE:
+ // '≠'
+ if ($value != $item->fields[$searchOption['linkfield']]){
+ return false;
+ }
+ break;
+ case self::SHOW_CONDITION_LT:
+ // '<';
+ if ($item->fields[$searchOption['linkfield']] > $value){
+ return false;
+ }
+ break;
+ case self::SHOW_CONDITION_GT:
+ //'>';
+ if ($item->fields[$searchOption['linkfield']] > $value){
+ return false;
+ }
+ break;
+ case self::SHOW_CONDITION_REGEX:
+ //'regex';
+ if(self::checkRegex($value)) {
+ $value = Sanitizer::unsanitize($value);
+ if (preg_match_all($value . "i", $item->fields[$searchOption['linkfield']]) > 0) {
+ return false;
+ }
+ }
+ break;
+ }
+ }
+ return true;
+ }
+
+
+ public static function checkRegex($regex) {
+ // Avoid php notice when validating the regular expression
+ set_error_handler(function ($errno, $errstr, $errfile, $errline, $errcontext) {
+ });
+ $isValid = !(preg_match($regex, null) === false);
+ restore_error_handler();
+ return $isValid;
+ }
+
+
+ public static function showForTabContainer(CommonGLPI $item, $options = []) {
+
+ $displayCondition_id = $options['displaycondition_id'] ?? 0;
+ $display_condition = null;
+
+ if ($displayCondition_id) {
+ $display_condition = new self();
+ $display_condition->getFromDB($displayCondition_id);
+ }
+
+ $container_id = $item->getID();
+ $twig_params = [
+ 'container_id' => $container_id,
+ 'container_display_conditions' => self::getDisplayConditionForContainer($container_id),
+ ];
+
+ TemplateRenderer::getInstance()->display('@fields/container_display_conditions.html.twig', $twig_params);
+ }
+
+ public function showForm($ID, array $options = []) {
+ $container_id = $options['plugin_fields_containers_id'];
+
+ $twig_params = [
+ 'container_display_condition' => $this,
+ 'container_id' => $container_id,
+ 'container_itemtypes' => self::getItemtypesForContainer($container_id),
+ 'search_options' => $this->isNewItem()
+ ? []
+ : self::removeBlackListedOption(Search::getOptions($this->fields['itemtype']), $this->fields['itemtype']),
+ ];
+ TemplateRenderer::getInstance()->display('@fields/forms/container_display_condition.html.twig', $twig_params);
+ }
+}
diff --git a/inc/field.class.php b/inc/field.class.php
index cfd89f8d..bc04f7c0 100644
--- a/inc/field.class.php
+++ b/inc/field.class.php
@@ -641,13 +641,18 @@ static function showForTab($params) {
return false;
}
- self::showDomContainer(
- $c_id,
- $item::getType(),
- $item->getID(),
- $type,
- $subtype
- );
+ $display_condition = new PluginFieldsContainerDisplayCondition();
+ if($display_condition->computeDisplayContainer($item, $c_id)) {
+ self::showDomContainer(
+ $c_id,
+ $item::getType(),
+ $item->getID(),
+ $type,
+ $subtype
+ );
+ }
+
+
}
static function prepareHtmlFields($fields, $items_id, $itemtype, $canedit = true,
diff --git a/templates/container_display_conditions.html.twig b/templates/container_display_conditions.html.twig
new file mode 100644
index 00000000..69ba5ff4
--- /dev/null
+++ b/templates/container_display_conditions.html.twig
@@ -0,0 +1,146 @@
+{#
+ # -------------------------------------------------------------------------
+ # 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
{{ __('Item type') }} | +{{ __('Field') }} | +{{ __('Condition') }} | +{{ __('Value') }} | ++ | |
---|---|---|---|---|---|
{{ container_display_condition.itemtype|itemtype_name }} | +{{ call('PluginFieldsContainerDisplayCondition::getFieldName', [container_display_condition.search_option, container_display_condition.itemtype]) }} | +{{ call('PluginFieldsContainerDisplayCondition::getConditionName', [container_display_condition.condition]) }} | +{{ call('PluginFieldsContainerDisplayCondition::getRawValue', [container_display_condition.search_option, container_display_condition.itemtype, container_display_condition.value]) }} | ++ + | +|
{{ __('No item found') }} | +