From c019983e08d426d9eeef660db2a2392c162323dc Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 8 Dec 2023 09:19:56 +0100 Subject: [PATCH 01/38] States genericity Add new relation table, Drop existign columns, Add migration, Adapt add/update Add tests --- .../update_10.0.x_to_11.0.0/states.php | 102 +++++++++++++++ install/mysql/glpi-empty.sql | 49 ++----- src/Appliance.php | 1 + src/Cable.php | 1 + src/Certificate.php | 1 + src/Cluster.php | 1 + src/Computer.php | 6 +- src/Contract.php | 1 + src/DatabaseInstance.php | 1 + src/Dropdown.php | 2 +- src/DropdownVisibility.php | 46 +++++++ src/Enclosure.php | 1 + src/Features/State.php | 120 ++++++++++++++++++ src/Line.php | 4 +- src/Monitor.php | 1 + src/NetworkEquipment.php | 1 + src/PDU.php | 1 + src/PassiveDCEquipment.php | 1 + src/Peripheral.php | 1 + src/Phone.php | 1 + src/Printer.php | 1 + src/Rack.php | 1 + src/SoftwareLicense.php | 1 + src/SoftwareVersion.php | 2 + src/State.php | 56 +++++++- src/Unmanaged.php | 1 + .../components/form/item_device.html.twig | 3 +- templates/generic_show_form.html.twig | 3 +- tests/functional/State.php | 110 ++++++++++++++++ 29 files changed, 468 insertions(+), 52 deletions(-) create mode 100644 install/migrations/update_10.0.x_to_11.0.0/states.php create mode 100644 src/DropdownVisibility.php create mode 100644 src/Features/State.php diff --git a/install/migrations/update_10.0.x_to_11.0.0/states.php b/install/migrations/update_10.0.x_to_11.0.0/states.php new file mode 100644 index 00000000000..39ed071f406 --- /dev/null +++ b/install/migrations/update_10.0.x_to_11.0.0/states.php @@ -0,0 +1,102 @@ +. + * + * --------------------------------------------------------------------- + */ + +/** + * @var \DBmysql $DB + * @var \Migration $migration + */ + +$default_charset = DBConnection::getDefaultCharset(); +$default_collation = DBConnection::getDefaultCollation(); +$default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); + +if (!$DB->tableExists('glpi_dropdownvisibilities')) { + $known_visibilities = [ + 'computer', + 'monitor', + 'networkequipment', + 'peripheral', + 'phone', + 'printer', + 'softwareversion', + 'softwarelicense', + 'line', + 'certificate', + 'rack', + 'passivedcequipment', + 'enclosure', + 'pdu', + 'cluster', + 'contract', + 'appliance', + 'databaseinstance', + 'cable', + 'unmanaged' + ]; + + $query = "CREATE TABLE `glpi_dropdownvisibilities` ( + `id` int {$default_key_sign} NOT NULL AUTO_INCREMENT, + `itemtype` varchar(100) NOT NULL DEFAULT '', + `items_id` int {$default_key_sign} NOT NULL DEFAULT '0', + `visible_itemtype` varchar(100) NOT NULL DEFAULT '', + `is_visible` tinyint NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + KEY `visible_itemtype` (`visible_itemtype`), + KEY `item` (`itemtype`,`items_id`) + ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; + $DB->doQueryOrDie($query, "10.1.0 add table glpi_dropdownvisibilities"); + + $states = $DB->request('glpi_states'); + foreach ($states as $state) { + $insert_data = [ + 'itemtype' => 'State', + 'items_id' => $state['id'], + ]; + + foreach ($known_visibilities as $known_visibility) { + if (isset($state['is_visible_' . $known_visibility])) { + $insert_data['visible_itemtype'] = $known_visibility; + $insert_data['is_visible'] = $state['is_visible_' . $known_visibility]; + $DB->doQueryOrDie($DB->buildInsert('glpi_statevisibilities', $insert_data)); + } + } + } + + foreach ($known_visibilities as $known_visibility) { + if ($DB->fieldExists('glpi_states', 'is_visible_' . $known_visibility)) { + $migration->dropField('glpi_states', 'is_visible_' . $known_visibility); + } + } +} diff --git a/install/mysql/glpi-empty.sql b/install/mysql/glpi-empty.sql index 25c957182fc..ec0c1ee8281 100644 --- a/install/mysql/glpi-empty.sql +++ b/install/mysql/glpi-empty.sql @@ -6990,25 +6990,6 @@ CREATE TABLE `glpi_states` ( `level` int NOT NULL DEFAULT '0', `ancestors_cache` longtext, `sons_cache` longtext, - `is_visible_computer` tinyint NOT NULL DEFAULT '1', - `is_visible_monitor` tinyint NOT NULL DEFAULT '1', - `is_visible_networkequipment` tinyint NOT NULL DEFAULT '1', - `is_visible_peripheral` tinyint NOT NULL DEFAULT '1', - `is_visible_phone` tinyint NOT NULL DEFAULT '1', - `is_visible_printer` tinyint NOT NULL DEFAULT '1', - `is_visible_softwareversion` tinyint NOT NULL DEFAULT '1', - `is_visible_softwarelicense` tinyint NOT NULL DEFAULT '1', - `is_visible_line` tinyint NOT NULL DEFAULT '1', - `is_visible_certificate` tinyint NOT NULL DEFAULT '1', - `is_visible_rack` tinyint NOT NULL DEFAULT '1', - `is_visible_passivedcequipment` tinyint NOT NULL DEFAULT '1', - `is_visible_enclosure` tinyint NOT NULL DEFAULT '1', - `is_visible_pdu` tinyint NOT NULL DEFAULT '1', - `is_visible_cluster` tinyint NOT NULL DEFAULT '1', - `is_visible_contract` tinyint NOT NULL DEFAULT '1', - `is_visible_appliance` tinyint NOT NULL DEFAULT '1', - `is_visible_databaseinstance` tinyint NOT NULL DEFAULT '1', - `is_visible_cable` tinyint NOT NULL DEFAULT '1', `is_visible_unmanaged` tinyint NOT NULL DEFAULT '1', `is_helpdesk_visible` tinyint NOT NULL DEFAULT '1', `date_mod` timestamp NULL DEFAULT NULL, @@ -7018,25 +6999,6 @@ CREATE TABLE `glpi_states` ( KEY `name` (`name`), KEY `entities_id` (`entities_id`), KEY `is_recursive` (`is_recursive`), - KEY `is_visible_computer` (`is_visible_computer`), - KEY `is_visible_monitor` (`is_visible_monitor`), - KEY `is_visible_networkequipment` (`is_visible_networkequipment`), - KEY `is_visible_peripheral` (`is_visible_peripheral`), - KEY `is_visible_phone` (`is_visible_phone`), - KEY `is_visible_printer` (`is_visible_printer`), - KEY `is_visible_softwareversion` (`is_visible_softwareversion`), - KEY `is_visible_softwarelicense` (`is_visible_softwarelicense`), - KEY `is_visible_line` (`is_visible_line`), - KEY `is_visible_certificate` (`is_visible_certificate`), - KEY `is_visible_rack` (`is_visible_rack`), - KEY `is_visible_passivedcequipment` (`is_visible_passivedcequipment`), - KEY `is_visible_enclosure` (`is_visible_enclosure`), - KEY `is_visible_pdu` (`is_visible_pdu`), - KEY `is_visible_cluster` (`is_visible_cluster`), - KEY `is_visible_contract` (`is_visible_contract`), - KEY `is_visible_appliance` (`is_visible_appliance`), - KEY `is_visible_databaseinstance` (`is_visible_databaseinstance`), - KEY `is_visible_cable` (`is_visible_cable`), KEY `is_visible_unmanaged` (`is_visible_unmanaged`), KEY `is_helpdesk_visible` (`is_helpdesk_visible`), KEY `date_mod` (`date_mod`), @@ -7044,6 +7006,17 @@ CREATE TABLE `glpi_states` ( KEY `level` (`level`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; +DROP TABLE IF EXISTS glpi_dropdownvisibilities; +CREATE TABLE `glpi_dropdownvisibilities` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `itemtype` varchar(100) NOT NULL DEFAULT '', + `items_id` int unsigned NOT NULL DEFAULT '0', + `visible_itemtype` varchar(100) NOT NULL DEFAULT '', + `is_visible` tinyint NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + KEY `visible_itemtype` (`visible_itemtype`), + KEY `item` (`itemtype`,`items_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; ### Dump table glpi_suppliers diff --git a/src/Appliance.php b/src/Appliance.php index 68a93a87c77..be8e28b63a5 100644 --- a/src/Appliance.php +++ b/src/Appliance.php @@ -42,6 +42,7 @@ class Appliance extends CommonDBTM { use Glpi\Features\Clonable; + use Glpi\Features\State; use AssetImage; // From CommonDBTM diff --git a/src/Cable.php b/src/Cable.php index 414b5c046d8..f1d08929446 100644 --- a/src/Cable.php +++ b/src/Cable.php @@ -41,6 +41,7 @@ class Cable extends CommonDBTM { use Glpi\Features\Clonable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/Certificate.php b/src/Certificate.php index cf217c2e57d..234b25516fe 100644 --- a/src/Certificate.php +++ b/src/Certificate.php @@ -49,6 +49,7 @@ class Certificate extends CommonDBTM { use Glpi\Features\Clonable; + use Glpi\Features\State; public $dohistory = true; public static $rightname = "certificate"; diff --git a/src/Cluster.php b/src/Cluster.php index 43af71bab5c..274c0cb7135 100644 --- a/src/Cluster.php +++ b/src/Cluster.php @@ -39,6 +39,7 @@ class Cluster extends CommonDBTM { use Glpi\Features\Clonable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/Computer.php b/src/Computer.php index f84a9c43b56..6c8afed56b0 100644 --- a/src/Computer.php +++ b/src/Computer.php @@ -43,6 +43,7 @@ class Computer extends CommonDBTM use Glpi\Features\DCBreadcrumb; use Glpi\Features\Clonable; use Glpi\Features\Inventoriable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; @@ -418,14 +419,15 @@ public function rawSearchOptions() 'datatype' => 'dropdown' ]; - $tab[] = [ + //FIXME: add a search option for the state + /*$tab[] = [ 'id' => '31', 'table' => 'glpi_states', 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', 'condition' => ['is_visible_computer' => 1] - ]; + ];*/ $tab[] = [ 'id' => '42', diff --git a/src/Contract.php b/src/Contract.php index 9a7684bb0d9..042569ca6c6 100644 --- a/src/Contract.php +++ b/src/Contract.php @@ -43,6 +43,7 @@ class Contract extends CommonDBTM { use Glpi\Features\Clonable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/DatabaseInstance.php b/src/DatabaseInstance.php index b8f8255f7d0..1bf381f99f0 100644 --- a/src/DatabaseInstance.php +++ b/src/DatabaseInstance.php @@ -39,6 +39,7 @@ class DatabaseInstance extends CommonDBTM { use Glpi\Features\Clonable; use Glpi\Features\Inventoriable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/Dropdown.php b/src/Dropdown.php index 02d33d14afe..6c2a9ef0120 100644 --- a/src/Dropdown.php +++ b/src/Dropdown.php @@ -2659,7 +2659,7 @@ public static function getDropdownValue($post, $json = true) */ global $CFG_GLPI, $DB; - // check if asked itemtype is the one originaly requested by the form + // check if asked itemtype is the one originally requested by the form if (!Session::validateIDOR($post)) { return; } diff --git a/src/DropdownVisibility.php b/src/DropdownVisibility.php new file mode 100644 index 00000000000..d6e122cfb6e --- /dev/null +++ b/src/DropdownVisibility.php @@ -0,0 +1,46 @@ +. + * + * --------------------------------------------------------------------- + */ + +use Glpi\Application\View\TemplateRenderer; +use Glpi\Dashboard\Widget; + +class DropdownVisibility extends CommonDBChild +{ + public static $mustBeAttached = false; //no idea why. + public static $itemtype = 'itemtype'; + public static $items_id = 'states_id'; + public $dohistory = false; + public static $logs_for_parent = false; +} diff --git a/src/Enclosure.php b/src/Enclosure.php index 818e249aae4..99041d4343b 100644 --- a/src/Enclosure.php +++ b/src/Enclosure.php @@ -42,6 +42,7 @@ class Enclosure extends CommonDBTM { use Glpi\Features\DCBreadcrumb; use Glpi\Features\Clonable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/Features/State.php b/src/Features/State.php new file mode 100644 index 00000000000..db6d9924c93 --- /dev/null +++ b/src/Features/State.php @@ -0,0 +1,120 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace Glpi\Features; + +use Agent; +use AutoUpdateSystem; +use CommonDBTM; +use Computer; +use Computer_Item; +use DatabaseInstance; +use Glpi\Inventory\Conf; +use Glpi\Plugin\Hooks; +use Html; +use Plugin; +use RefusedEquipment; + +trait State +{ + /** + * Check if itemtype class is present in configuration array + * + * @return void + */ + protected function checkSetup(): void + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + if (!in_array(get_class($this), $CFG_GLPI['state_types'])) { + trigger_error( + sprintf( + 'Class %s must be present in $CFG_GLPI[\'state_types\']', + get_class($this) + ), + E_USER_ERROR + ); + } + } + + /** + * Get the visibility of the state field for the item + * + * @param int $id State ID + * + * @return bool + */ + public function isStateVisible(int $id): bool + { + $this->checkSetup(); + $dropdownVisibility = new \DropdownVisibility(); + return $dropdownVisibility->getFromDBByCrit([ + 'itemtype' => \State::getType(), + 'items_id' => $id, + 'visible_itemtype' => get_class($this), + 'is_visible' => 1 + ]); + } + + /** + * Get the visibility criteria of the state field to use a filter condition + * + * @return array + */ + public function getVisibilityCriteria(): array + { + $this->checkSetup(); + return [ + 'LEFT JOIN' => [ + \DropdownVisibility::getTable() => [ + 'ON' => [ + \DropdownVisibility::getTable() => 'items_id', + \State::getTable() => 'id', [ + 'AND' => [ + \DropdownVisibility::getTable() . '.itemtype' => \State::getType() + ] + ] + ] + ] + ], + 'WHERE' => [ + \DropdownVisibility::getTable() . '.itemtype' => \State::getType(), + \DropdownVisibility::getTable() . '.visible_itemtype' => get_class($this), + \DropdownVisibility::getTable() . '.is_visible' => 1 + ] + ]; + } +} diff --git a/src/Line.php b/src/Line.php index 57d75c68409..10a7b6343a1 100644 --- a/src/Line.php +++ b/src/Line.php @@ -42,7 +42,9 @@ class Line extends CommonDBTM { - // From CommonDBTM + use Glpi\Features\State; + + // From CommonDBTM public $dohistory = true; public static $rightname = 'line'; diff --git a/src/Monitor.php b/src/Monitor.php index 204445f01ba..218b2d5af8b 100644 --- a/src/Monitor.php +++ b/src/Monitor.php @@ -43,6 +43,7 @@ class Monitor extends CommonDBTM use Glpi\Features\DCBreadcrumb; use Glpi\Features\Clonable; use Glpi\Features\Inventoriable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/NetworkEquipment.php b/src/NetworkEquipment.php index d17097c4d07..10276b0afa9 100644 --- a/src/NetworkEquipment.php +++ b/src/NetworkEquipment.php @@ -45,6 +45,7 @@ class NetworkEquipment extends CommonDBTM use Glpi\Features\DCBreadcrumb; use Glpi\Features\Clonable; use Glpi\Features\Inventoriable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/PDU.php b/src/PDU.php index e145f706b1d..6f4a8e35047 100644 --- a/src/PDU.php +++ b/src/PDU.php @@ -40,6 +40,7 @@ class PDU extends CommonDBTM { use Glpi\Features\DCBreadcrumb; use Glpi\Features\Clonable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/PassiveDCEquipment.php b/src/PassiveDCEquipment.php index ec69079c023..9c97a93a89b 100644 --- a/src/PassiveDCEquipment.php +++ b/src/PassiveDCEquipment.php @@ -43,6 +43,7 @@ class PassiveDCEquipment extends CommonDBTM { use Clonable; use Glpi\Features\DCBreadcrumb; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/Peripheral.php b/src/Peripheral.php index 5d5c3c08177..ed10141b362 100644 --- a/src/Peripheral.php +++ b/src/Peripheral.php @@ -43,6 +43,7 @@ class Peripheral extends CommonDBTM use Glpi\Features\DCBreadcrumb; use Glpi\Features\Clonable; use Glpi\Features\Inventoriable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/Phone.php b/src/Phone.php index 4ac80b57132..125967daed0 100644 --- a/src/Phone.php +++ b/src/Phone.php @@ -43,6 +43,7 @@ class Phone extends CommonDBTM { use Glpi\Features\Clonable; use Glpi\Features\Inventoriable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/Printer.php b/src/Printer.php index b1c5511136a..af54cdd4d12 100644 --- a/src/Printer.php +++ b/src/Printer.php @@ -45,6 +45,7 @@ class Printer extends CommonDBTM { use Glpi\Features\Clonable; use Glpi\Features\Inventoriable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/src/Rack.php b/src/Rack.php index 4be46541d75..39f8aa58cb2 100644 --- a/src/Rack.php +++ b/src/Rack.php @@ -41,6 +41,7 @@ class Rack extends CommonDBTM { use Glpi\Features\DCBreadcrumb; + use Glpi\Features\State; const FRONT = 0; const REAR = 1; diff --git a/src/SoftwareLicense.php b/src/SoftwareLicense.php index b58283b64d8..40a8fe275fb 100644 --- a/src/SoftwareLicense.php +++ b/src/SoftwareLicense.php @@ -44,6 +44,7 @@ class SoftwareLicense extends CommonTreeDropdown { use Glpi\Features\Clonable; + use Glpi\Features\State; use AssetImage; /// TODO move to CommonDBChild ? diff --git a/src/SoftwareVersion.php b/src/SoftwareVersion.php index 9924ab7e9a7..0d6a3114447 100644 --- a/src/SoftwareVersion.php +++ b/src/SoftwareVersion.php @@ -38,6 +38,8 @@ **/ class SoftwareVersion extends CommonDBChild { + use Glpi\Features\State; + // From CommonDBTM public $dohistory = true; diff --git a/src/State.php b/src/State.php index 14912d4ea7b..4183fe3f9da 100644 --- a/src/State.php +++ b/src/State.php @@ -302,11 +302,6 @@ public function cleanDBonPurge() } - /** - * @since 0.85 - * - * @see CommonTreeDropdown::prepareInputForAdd() - **/ public function prepareInputForAdd($input) { if (!isset($input['states_id'])) { @@ -324,7 +319,7 @@ public function prepareInputForAdd($input) $input = parent::prepareInputForAdd($input); $state = new self(); - // Get visibility information from parent if not set + // Get visibility information from parent if not set if (isset($input['states_id']) && $state->getFromDB($input['states_id'])) { foreach ($this->getvisibilityFields() as $type => $field) { if (!isset($input[$field]) && isset($state->fields[$field])) { @@ -335,6 +330,46 @@ public function prepareInputForAdd($input) return $input; } + public function post_addItem() + { + $state_visilibity = new DropdownVisibility(); + foreach ($this->getvisibilityFields() as $itemtype => $field) { + if (isset($this->input[$field])) { + $state_visilibity->add([ + 'itemtype' => State::getType(), + 'items_id' => $this->fields['id'], + 'visible_itemtype' => $itemtype, + 'is_visible' => $this->input[$field] + ]); + } + } + + parent::post_addItem(); + } + + public function post_updateItem($history = true) + { + $state_visilibity = new DropdownVisibility(); + foreach ($this->getvisibilityFields() as $itemtype => $field) { + if (isset($this->input[$field])) { + if ($state_visilibity->getFromDBByCrit(['itemtype' => self::getType(), 'items_id' => $this->input['id'], 'visible_itemtype' => $itemtype])) { + $state_visilibity->update([ + 'id' => $state_visilibity->fields['id'], + 'is_visible' => $this->input[$field] + ]); + } else { + $state_visilibity->add([ + 'itemtype' => State::getType(), + 'items_id' => $this->fields['id'], + 'visible_itemtype' => $itemtype, + 'is_visible' => $this->input[$field] + ]); + } + } + } + + parent::post_updateItem(); + } public function rawSearchOptions() { @@ -659,4 +694,13 @@ public function getCloneRelations(): array { return []; } + + public function post_getFromDB() + { + $statevisibility = new DropdownVisibility(); + $visibilities = $statevisibility->find(['itemtype' => State::getType(), 'items_id' => $this->fields['id']]); + foreach ($visibilities as $visibility) { + $this->fields['is_visible_' . strtolower($visibility['visible_itemtype'])] = $visibility['is_visible']; + } + } } diff --git a/src/Unmanaged.php b/src/Unmanaged.php index 405e4680dd4..c7fc4dc68d8 100644 --- a/src/Unmanaged.php +++ b/src/Unmanaged.php @@ -42,6 +42,7 @@ class Unmanaged extends CommonDBTM { use Glpi\Features\Inventoriable; + use Glpi\Features\State; // From CommonDBTM public $dohistory = true; diff --git a/templates/components/form/item_device.html.twig b/templates/components/form/item_device.html.twig index df8919f238a..680f4482e17 100644 --- a/templates/components/form/item_device.html.twig +++ b/templates/components/form/item_device.html.twig @@ -183,7 +183,6 @@ {% endif %} {% if item.isField('states_id') %} - {% set condition = item.getType() in config('state_types') ? {('is_visible_' ~ item.getType()|lower): 1} : {} %} {{ fields.dropdownField( 'State', 'states_id', @@ -191,7 +190,7 @@ __('Status'), field_options|merge({ 'entity': item.fields['entities_id'], - 'condition': condition + 'condition': item.getVisibilityCriteria() ?? {} }) ) }} {% endif %} diff --git a/templates/generic_show_form.html.twig b/templates/generic_show_form.html.twig index aa4268f8902..be928db10d0 100644 --- a/templates/generic_show_form.html.twig +++ b/templates/generic_show_form.html.twig @@ -98,7 +98,6 @@ {% endif %} {% if item.isField('states_id') %} - {% set condition = item.getType() in config('state_types') ? {('is_visible_' ~ item.getType()|lower): 1} : {} %} {{ fields.dropdownField( 'State', 'states_id', @@ -106,7 +105,7 @@ __('Status'), field_options|merge({ 'entity': item.fields['entities_id'], - 'condition': condition + 'condition': item.getVisibilityCriteria() ?? {} }) ) }} {% endif %} diff --git a/tests/functional/State.php b/tests/functional/State.php index 93b0ccaf591..bc84fff7e97 100644 --- a/tests/functional/State.php +++ b/tests/functional/State.php @@ -83,4 +83,114 @@ public function testIsUnique(array $input, bool $expected) $state = new \State(); $this->boolean($state->isUnique($input))->isEqualTo($expected); } + + public function testVisibility() + { + $state = new \State(); + + $states_id = $state->add([ + 'name' => 'Test computer and phone', + 'is_visible_computer' => '1', + 'is_visible_phone' => '1', + ]); + + $this->integer($states_id)->isGreaterThan(0); + + $statevisibility = new \DropdownVisibility(); + $visibilities = $statevisibility->find(['itemtype' => \State::getType(), 'items_id' => $states_id]); + $this->array($visibilities)->hasSize(2); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Computer::getType(), 'is_visible' => 1]))->isTrue(); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Phone::getType(), 'is_visible' => 1]))->isTrue(); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Printer::getType(), 'is_visible' => 0]))->isFalse(); + + $state->update([ + 'id' => $states_id, + 'is_visible_computer' => '0', + 'is_visible_printer' => '1', + ]); + $visibilities = $statevisibility->find(['itemtype' => \State::getType(), 'items_id' => $states_id]); + $this->array($visibilities)->hasSize(3); + $visibilities = $statevisibility->find(['itemtype' => \State::getType(), 'items_id' => $states_id, 'is_visible' => 1]); + $this->array($visibilities)->hasSize(2); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Computer::getType(), 'is_visible' => 0]))->isTrue(); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Phone::getType(), 'is_visible' => 1]))->isTrue(); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Printer::getType(), 'is_visible' => 1]))->isTrue(); + + $this->boolean($state->getFromDB($states_id))->isTrue(); + $this->string($state->fields['name'])->isEqualTo('Test computer and phone'); + $this->integer($state->fields['is_visible_computer'])->isIdenticalTo(0); + $this->integer($state->fields['is_visible_phone'])->isIdenticalTo(1); + $this->integer($state->fields['is_visible_printer'])->isIdenticalTo(1); + } + + public function testHasFeature() + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + foreach ($CFG_GLPI['state_types'] as $itemtype) { + $this->boolean(method_exists($itemtype, 'isStateVisible'))->isTrue($itemtype . ' misses isStateVisible() method!'); + } + } + + public function testIsStateVisible() + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + $state = new \State(); + $states_id = $state->add([ + 'name' => 'Test computer and phone', + 'is_visible_computer' => '1' + ]); + $this->integer($states_id)->isGreaterThan(0); + + $itemtype = $CFG_GLPI['state_types'][0]; + + $item = new $itemtype(); + $this->boolean(method_exists($itemtype, 'isStateVisible'))->isTrue($itemtype . ' misses isStateVisible() method!'); + $this->boolean($item->isStateVisible($states_id))->isTrue(); + + unset($CFG_GLPI['state_types'][0]); + $this->boolean(method_exists($itemtype, 'isStateVisible'))->isTrue($itemtype . ' misses isStateVisible() method!'); + + $this->when( + function() use ($item, $states_id) { + $this->boolean($item->isStateVisible($states_id))->isTrue(); + } + ) + ->error() + ->withType(E_USER_ERROR) + ->withMessage('Class Computer must be present in $CFG_GLPI[\'state_types\']') + ->exists(); + } + + public function testGetVisibilityCriteria() + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + $itemtype = $CFG_GLPI['state_types'][0]; + + $item = new $itemtype(); + $this->array($item->getVisibilityCriteria())->isIdenticalTo([ + 'LEFT JOIN' => [ + \DropdownVisibility::getTable() => [ + 'ON' => [ + \DropdownVisibility::getTable() => 'items_id', + \State::getTable() => 'id', [ + 'AND' => [ + \DropdownVisibility::getTable() . '.itemtype' => \State::getType() + ] + ] + ] + ] + ], + 'WHERE' => [ + \DropdownVisibility::getTable() . '.itemtype' => \State::getType(), + \DropdownVisibility::getTable() . '.visible_itemtype' => $itemtype, + \DropdownVisibility::getTable() . '.is_visible' => 1 + ] + ]); + } } From 3d411f915e9e7a4d09b4e8ec2cda1fd00e3ef1f3 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 8 Dec 2023 15:59:11 +0100 Subject: [PATCH 02/38] Fix SO on computer --- src/Computer.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Computer.php b/src/Computer.php index 6c8afed56b0..84247c1ea89 100644 --- a/src/Computer.php +++ b/src/Computer.php @@ -196,7 +196,7 @@ public function post_updateItem($history = true) ) { $changes['states_id'] = $input['states_id']; } - // Update loction of attached items + // Update location of attached items if ( $this->updates[$i] == 'locations_id' && Entity::getUsedConfig('is_location_autoupdate', $this->getEntityID()) @@ -426,8 +426,20 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_computer' => 1] - ];*/ + 'joinparams' => [ + 'beforejoin' => [ + 'table' => StateVisibility::getTable(), + 'joinparams' => [ + 'jointype' => 'child', + 'beforejoin' => [ + 'table' => State::getTable(), + ], + 'condition' => [ + 'NEWTABLE.itemtype' => 'Computer' + ] + ] + ] + ] $tab[] = [ 'id' => '42', From 51953e0d8ee26bb0e58fa019b885eccb3b9da8e7 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Thu, 14 Dec 2023 15:58:12 +0100 Subject: [PATCH 03/38] Try to replace SO (does not work, as usual) --- src/State.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/State.php b/src/State.php index 4183fe3f9da..2735cebc41a 100644 --- a/src/State.php +++ b/src/State.php @@ -397,10 +397,17 @@ public function rawSearchOptions() $tab[] = [ 'id' => '23', - 'table' => $this->getTable(), - 'field' => 'is_visible_monitor', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf(__('%1$s - %2$s'), __('Visibility'), Monitor::getTypeName(Session::getPluralNumber())), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Monitor' + ] + ] ]; $tab[] = [ From 4bcceb1151ab624426f361b4dc9679b45158fdf5 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Wed, 10 Jan 2024 08:22:23 +0100 Subject: [PATCH 04/38] Fix rebase --- src/Computer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Computer.php b/src/Computer.php index 84247c1ea89..191d4ac34a0 100644 --- a/src/Computer.php +++ b/src/Computer.php @@ -440,6 +440,7 @@ public function rawSearchOptions() ] ] ] + */ $tab[] = [ 'id' => '42', From adece9f1cf71733f2148f711b812222d730cfd63 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Wed, 10 Jan 2024 08:39:28 +0100 Subject: [PATCH 05/38] CS --- tests/functional/State.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/functional/State.php b/tests/functional/State.php index bc84fff7e97..d64c76c4e72 100644 --- a/tests/functional/State.php +++ b/tests/functional/State.php @@ -155,7 +155,8 @@ public function testIsStateVisible() $this->boolean(method_exists($itemtype, 'isStateVisible'))->isTrue($itemtype . ' misses isStateVisible() method!'); $this->when( - function() use ($item, $states_id) { + function() use ($item, $states_id) + { $this->boolean($item->isStateVisible($states_id))->isTrue(); } ) From 20bd277e4c43eb1adbec6a446082f86f09d5b7f7 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Wed, 10 Jan 2024 08:41:52 +0100 Subject: [PATCH 06/38] Fix empty schema --- install/mysql/glpi-empty.sql | 2 -- 1 file changed, 2 deletions(-) diff --git a/install/mysql/glpi-empty.sql b/install/mysql/glpi-empty.sql index ec0c1ee8281..b0339e3e5e6 100644 --- a/install/mysql/glpi-empty.sql +++ b/install/mysql/glpi-empty.sql @@ -6990,7 +6990,6 @@ CREATE TABLE `glpi_states` ( `level` int NOT NULL DEFAULT '0', `ancestors_cache` longtext, `sons_cache` longtext, - `is_visible_unmanaged` tinyint NOT NULL DEFAULT '1', `is_helpdesk_visible` tinyint NOT NULL DEFAULT '1', `date_mod` timestamp NULL DEFAULT NULL, `date_creation` timestamp NULL DEFAULT NULL, @@ -6999,7 +6998,6 @@ CREATE TABLE `glpi_states` ( KEY `name` (`name`), KEY `entities_id` (`entities_id`), KEY `is_recursive` (`is_recursive`), - KEY `is_visible_unmanaged` (`is_visible_unmanaged`), KEY `is_helpdesk_visible` (`is_helpdesk_visible`), KEY `date_mod` (`date_mod`), KEY `date_creation` (`date_creation`), From e7edc6edc579655006fa6e3787e0582c0cd4fb3b Mon Sep 17 00:00:00 2001 From: Alexandre Delaunay Date: Thu, 11 Jan 2024 11:39:38 +0100 Subject: [PATCH 07/38] fix table name --- install/migrations/update_10.0.x_to_11.0.0/states.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/migrations/update_10.0.x_to_11.0.0/states.php b/install/migrations/update_10.0.x_to_11.0.0/states.php index 39ed071f406..b74d4a1c1a0 100644 --- a/install/migrations/update_10.0.x_to_11.0.0/states.php +++ b/install/migrations/update_10.0.x_to_11.0.0/states.php @@ -89,7 +89,7 @@ if (isset($state['is_visible_' . $known_visibility])) { $insert_data['visible_itemtype'] = $known_visibility; $insert_data['is_visible'] = $state['is_visible_' . $known_visibility]; - $DB->doQueryOrDie($DB->buildInsert('glpi_statevisibilities', $insert_data)); + $DB->doQueryOrDie($DB->buildInsert('glpi_dropdownvisibilities', $insert_data)); } } } From 89f5778bdfc6f57829b5d6617d76d97aed31f0cd Mon Sep 17 00:00:00 2001 From: Alexandre Delaunay Date: Fri, 12 Jan 2024 09:01:36 +0100 Subject: [PATCH 08/38] almost ok SO for computer --- src/Computer.php | 22 ++++++++++------------ src/DBmysqlIterator.php | 2 +- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/Computer.php b/src/Computer.php index 191d4ac34a0..343f0386c97 100644 --- a/src/Computer.php +++ b/src/Computer.php @@ -419,28 +419,26 @@ public function rawSearchOptions() 'datatype' => 'dropdown' ]; - //FIXME: add a search option for the state - /*$tab[] = [ + $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', 'joinparams' => [ + 'condition' => [ + '`glpi_computers`.`states_id`' => '`NEWTABLE`.`id`', + ], + 'jointype' => 'itemtype_item_revert', + 'specific_itemtype' => State::getType(), 'beforejoin' => [ - 'table' => StateVisibility::getTable(), + 'table' => DropdownVisibility::getTable(), 'joinparams' => [ - 'jointype' => 'child', - 'beforejoin' => [ - 'table' => State::getTable(), - ], - 'condition' => [ - 'NEWTABLE.itemtype' => 'Computer' - ] + 'jointype' => 'itemtypeonly', ] ] ] - */ + ]; $tab[] = [ 'id' => '42', diff --git a/src/DBmysqlIterator.php b/src/DBmysqlIterator.php index 19380971f4a..a4c8fdb177f 100644 --- a/src/DBmysqlIterator.php +++ b/src/DBmysqlIterator.php @@ -727,7 +727,7 @@ private function analyseFkey($values) } else if (count($values) == 3) { $condition = array_pop($values); $fkey = $this->analyseFkey($values); - $condition_value = $this->analyseCrit(current($condition)); + $condition_value = $this->analyseCrit($condition); if (!empty(trim($condition_value))) { return $fkey . ' ' . key($condition) . ' ' . $condition_value; } From dd83aaaa18cfb812d5a8c203ed2897acb9b35d00 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Wed, 10 Jan 2024 08:48:17 +0100 Subject: [PATCH 09/38] Fix CS --- tests/functional/State.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/functional/State.php b/tests/functional/State.php index d64c76c4e72..7037f801595 100644 --- a/tests/functional/State.php +++ b/tests/functional/State.php @@ -155,8 +155,7 @@ public function testIsStateVisible() $this->boolean(method_exists($itemtype, 'isStateVisible'))->isTrue($itemtype . ' misses isStateVisible() method!'); $this->when( - function() use ($item, $states_id) - { + function () use ($item, $states_id) { $this->boolean($item->isStateVisible($states_id))->isTrue(); } ) From 4a9c47791ab37c888c796e5e43740638d5cddc07 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 12 Jan 2024 13:41:58 +0100 Subject: [PATCH 10/38] Fix headers --- install/migrations/update_10.0.x_to_11.0.0/states.php | 2 +- src/DropdownVisibility.php | 2 +- src/Features/State.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/install/migrations/update_10.0.x_to_11.0.0/states.php b/install/migrations/update_10.0.x_to_11.0.0/states.php index b74d4a1c1a0..4eb869b5146 100644 --- a/install/migrations/update_10.0.x_to_11.0.0/states.php +++ b/install/migrations/update_10.0.x_to_11.0.0/states.php @@ -7,7 +7,7 @@ * * http://glpi-project.org * - * @copyright 2015-2023 Teclib' and contributors. + * @copyright 2015-2024 Teclib' and contributors. * @copyright 2003-2014 by the INDEPNET Development Team. * @licence https://www.gnu.org/licenses/gpl-3.0.html * diff --git a/src/DropdownVisibility.php b/src/DropdownVisibility.php index d6e122cfb6e..d8d52f6535d 100644 --- a/src/DropdownVisibility.php +++ b/src/DropdownVisibility.php @@ -7,7 +7,7 @@ * * http://glpi-project.org * - * @copyright 2015-2023 Teclib' and contributors. + * @copyright 2015-2024 Teclib' and contributors. * @copyright 2003-2014 by the INDEPNET Development Team. * @licence https://www.gnu.org/licenses/gpl-3.0.html * diff --git a/src/Features/State.php b/src/Features/State.php index db6d9924c93..49d80bc60b7 100644 --- a/src/Features/State.php +++ b/src/Features/State.php @@ -7,7 +7,7 @@ * * http://glpi-project.org * - * @copyright 2015-2023 Teclib' and contributors. + * @copyright 2015-2024 Teclib' and contributors. * @copyright 2003-2014 by the INDEPNET Development Team. * @licence https://www.gnu.org/licenses/gpl-3.0.html * From f6ef4ea93a04a2f3dc3553311221fc90e96d2727 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 12 Jan 2024 14:45:25 +0100 Subject: [PATCH 11/38] Fix query error --- src/Computer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Computer.php b/src/Computer.php index 343f0386c97..aa6e34930ba 100644 --- a/src/Computer.php +++ b/src/Computer.php @@ -427,7 +427,7 @@ public function rawSearchOptions() 'datatype' => 'dropdown', 'joinparams' => [ 'condition' => [ - '`glpi_computers`.`states_id`' => '`NEWTABLE`.`id`', + '`glpi_computers`.`states_id`' => new \Glpi\DBAL\QueryExpression('`NEWTABLE`.`id`'), ], 'jointype' => 'itemtype_item_revert', 'specific_itemtype' => State::getType(), From 41d30535e0733ceb1673c881211d78bda55d6974 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Thu, 22 Feb 2024 09:05:49 +0100 Subject: [PATCH 12/38] Fix CS --- src/State.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/State.php b/src/State.php index 2735cebc41a..de0b1b57f3e 100644 --- a/src/State.php +++ b/src/State.php @@ -701,7 +701,7 @@ public function getCloneRelations(): array { return []; } - + public function post_getFromDB() { $statevisibility = new DropdownVisibility(); From 44dd0ae27cda807a4a91d9db77745f6663111a4e Mon Sep 17 00:00:00 2001 From: Alexandre Delaunay Date: Thu, 22 Feb 2024 11:49:08 +0100 Subject: [PATCH 13/38] fix SO --- src/Computer.php | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Computer.php b/src/Computer.php index aa6e34930ba..904642504ec 100644 --- a/src/Computer.php +++ b/src/Computer.php @@ -425,19 +425,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'joinparams' => [ - 'condition' => [ - '`glpi_computers`.`states_id`' => new \Glpi\DBAL\QueryExpression('`NEWTABLE`.`id`'), - ], - 'jointype' => 'itemtype_item_revert', - 'specific_itemtype' => State::getType(), - 'beforejoin' => [ - 'table' => DropdownVisibility::getTable(), - 'joinparams' => [ - 'jointype' => 'itemtypeonly', - ] - ] - ] + 'condition' => self::getVisibilityCriteria(), ]; $tab[] = [ From 2a690bfd470124e8a5b5e354bed9b73688dc80c6 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Thu, 22 Feb 2024 14:02:14 +0100 Subject: [PATCH 14/38] Rename method --- src/Computer.php | 2 +- src/Features/State.php | 2 +- templates/components/form/item_device.html.twig | 2 +- templates/generic_show_form.html.twig | 2 +- tests/functional/State.php | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Computer.php b/src/Computer.php index 904642504ec..6b6a7c3a241 100644 --- a/src/Computer.php +++ b/src/Computer.php @@ -425,7 +425,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getVisibilityCriteria(), + 'condition' => self::getStateVisibilityCriteria(), ]; $tab[] = [ diff --git a/src/Features/State.php b/src/Features/State.php index 49d80bc60b7..d2b728d77bc 100644 --- a/src/Features/State.php +++ b/src/Features/State.php @@ -94,7 +94,7 @@ public function isStateVisible(int $id): bool * * @return array */ - public function getVisibilityCriteria(): array + public function getStateVisibilityCriteria(): array { $this->checkSetup(); return [ diff --git a/templates/components/form/item_device.html.twig b/templates/components/form/item_device.html.twig index 680f4482e17..d72d39a757e 100644 --- a/templates/components/form/item_device.html.twig +++ b/templates/components/form/item_device.html.twig @@ -190,7 +190,7 @@ __('Status'), field_options|merge({ 'entity': item.fields['entities_id'], - 'condition': item.getVisibilityCriteria() ?? {} + 'condition': item.getStateVisibilityCriteria() ?? {} }) ) }} {% endif %} diff --git a/templates/generic_show_form.html.twig b/templates/generic_show_form.html.twig index be928db10d0..eea7468502f 100644 --- a/templates/generic_show_form.html.twig +++ b/templates/generic_show_form.html.twig @@ -105,7 +105,7 @@ __('Status'), field_options|merge({ 'entity': item.fields['entities_id'], - 'condition': item.getVisibilityCriteria() ?? {} + 'condition': item.getStateVisibilityCriteria() ?? {} }) ) }} {% endif %} diff --git a/tests/functional/State.php b/tests/functional/State.php index 7037f801595..eadedbc5f10 100644 --- a/tests/functional/State.php +++ b/tests/functional/State.php @@ -165,7 +165,7 @@ function () use ($item, $states_id) { ->exists(); } - public function testGetVisibilityCriteria() + public function testGetStateVisibilityCriteria() { /** @var array $CFG_GLPI */ global $CFG_GLPI; @@ -173,7 +173,7 @@ public function testGetVisibilityCriteria() $itemtype = $CFG_GLPI['state_types'][0]; $item = new $itemtype(); - $this->array($item->getVisibilityCriteria())->isIdenticalTo([ + $this->array($item->getStateVisibilityCriteria())->isIdenticalTo([ 'LEFT JOIN' => [ \DropdownVisibility::getTable() => [ 'ON' => [ From 4ae196c2052ed3568add21a224c21fd8bdf80593 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Thu, 22 Feb 2024 15:02:55 +0100 Subject: [PATCH 15/38] Revert useless change --- src/DBmysqlIterator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DBmysqlIterator.php b/src/DBmysqlIterator.php index a4c8fdb177f..19380971f4a 100644 --- a/src/DBmysqlIterator.php +++ b/src/DBmysqlIterator.php @@ -727,7 +727,7 @@ private function analyseFkey($values) } else if (count($values) == 3) { $condition = array_pop($values); $fkey = $this->analyseFkey($values); - $condition_value = $this->analyseCrit($condition); + $condition_value = $this->analyseCrit(current($condition)); if (!empty(trim($condition_value))) { return $fkey . ' ' . key($condition) . ' ' . $condition_value; } From fd197979c4236ce0b8823c1f0aaf7601bf255d81 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Thu, 22 Feb 2024 15:03:39 +0100 Subject: [PATCH 16/38] Fix condition \\o// --- src/Features/State.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/State.php b/src/Features/State.php index d2b728d77bc..139d457b922 100644 --- a/src/Features/State.php +++ b/src/Features/State.php @@ -102,7 +102,7 @@ public function getStateVisibilityCriteria(): array \DropdownVisibility::getTable() => [ 'ON' => [ \DropdownVisibility::getTable() => 'items_id', - \State::getTable() => 'id', [ + \State::getTable() => 'id', 'zzz' => [ 'AND' => [ \DropdownVisibility::getTable() . '.itemtype' => \State::getType() ] From 7d7e7b1961457db204b3f30dd29b71d23aea75c1 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Thu, 22 Feb 2024 15:27:13 +0100 Subject: [PATCH 17/38] "Improve" FKEY condition detection Error if condition has not been found All parts but condition **must** be associative array entries... --- src/DBmysqlIterator.php | 15 +++++++-- src/Features/State.php | 2 +- src/Search/Provider/SQLProvider.php | 4 +-- tests/units/DBmysqlIterator.php | 47 ++++++++++++++++++++++++++++- 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/DBmysqlIterator.php b/src/DBmysqlIterator.php index 19380971f4a..9fb693d82ad 100644 --- a/src/DBmysqlIterator.php +++ b/src/DBmysqlIterator.php @@ -725,8 +725,19 @@ private function analyseFkey($values) (is_numeric($t2) ? DBmysql::quoteName($f2) : DBmysql::quoteName($t2) . '.' . DBmysql::quoteName($f2)); } } else if (count($values) == 3) { - $condition = array_pop($values); - $fkey = $this->analyseFkey($values); + $real_values = []; + foreach ($values as $k => $v) { + if (is_string($k)) { + $real_values[$k] = $v; + } else { + $condition = $v; + } + } + if (count($real_values) != 2 || !isset($condition)) { + throw new \LogicException('BAD FOREIGN KEY, should be [ table1 => key1, table2 => key2 ] or [ table1 => key1, table2 => key2, [criteria]].'); + } + //$condition = array_pop($real_values); + $fkey = $this->analyseFkey($real_values); $condition_value = $this->analyseCrit(current($condition)); if (!empty(trim($condition_value))) { return $fkey . ' ' . key($condition) . ' ' . $condition_value; diff --git a/src/Features/State.php b/src/Features/State.php index 139d457b922..d2b728d77bc 100644 --- a/src/Features/State.php +++ b/src/Features/State.php @@ -102,7 +102,7 @@ public function getStateVisibilityCriteria(): array \DropdownVisibility::getTable() => [ 'ON' => [ \DropdownVisibility::getTable() => 'items_id', - \State::getTable() => 'id', 'zzz' => [ + \State::getTable() => 'id', [ 'AND' => [ \DropdownVisibility::getTable() . '.itemtype' => \State::getType() ] diff --git a/src/Search/Provider/SQLProvider.php b/src/Search/Provider/SQLProvider.php index dfbe908ee70..b29d41d1ea0 100644 --- a/src/Search/Provider/SQLProvider.php +++ b/src/Search/Provider/SQLProvider.php @@ -2652,7 +2652,7 @@ public static function getLeftJoinCriteria( "$new_table$AS" => [ 'ON' => [ $nt => 'itemtype', - new QueryExpression("'$used_itemtype'"), + 'qexp' => new QueryExpression("'$used_itemtype'"), ] ] ] @@ -3169,7 +3169,7 @@ public static function getDropdownTranslationJoinCriteria($alias, $table, $itemt "glpi_dropdowntranslations AS $alias" => [ 'ON' => [ $alias => 'itemtype', - new QueryExpression("'$itemtype'"), + 'qexp' => new QueryExpression("'$itemtype'"), [ 'AND' => [ "$alias.items_id" => "$table.id", diff --git a/tests/units/DBmysqlIterator.php b/tests/units/DBmysqlIterator.php index 44f7e3e2593..00ca0cae76e 100644 --- a/tests/units/DBmysqlIterator.php +++ b/tests/units/DBmysqlIterator.php @@ -480,7 +480,52 @@ function () { 'SELECT * FROM `foo` LEFT JOIN `bar` ON (`bar`.`id` = `foo`.`fk` AND `field` = \'42\')' ); - //test derived table in JOIN statement + //order in fkey should not matter + $it = $this->it->execute( + 'foo', + [ + 'LEFT JOIN' => [ + 'bar' => [ + 'FKEY' => [ + [ + 'AND' => ['field' => 42] + ], + 'bar' => 'id', + 'foo' => 'fk' + ] + ] + ] + ] + ); + $this->string($it->getSql())->isIdenticalTo( + 'SELECT * FROM `foo` LEFT JOIN `bar` ON (`bar`.`id` = `foo`.`fk` AND `field` = \'42\')' + ); + + //fail with condition set as associative array + $this->exception( + function () { + $it = $this->it->execute( + 'foo', + [ + 'LEFT JOIN' => [ + 'bar' => [ + 'FKEY' => [ + 'bar' => 'id', + 'foo' => 'fk', + 'zzz' => [ + 'AND' => ['field' => 42] + ] + ] + ] + ] + ] + ); + } + ) + ->isInstanceOf('LogicException') + ->hasMessage('BAD FOREIGN KEY, should be [ table1 => key1, table2 => key2 ] or [ table1 => key1, table2 => key2, [criteria]].'); + + //test derived table in JOIN statement $it = $this->it->execute( 'foo', [ From a6fe8c7e8859e508e667778a57d6270b55656adb Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Thu, 22 Feb 2024 15:47:45 +0100 Subject: [PATCH 18/38] Fix test --- tests/functional/Dropdown.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/functional/Dropdown.php b/tests/functional/Dropdown.php index 9950015d751..ead9c966300 100644 --- a/tests/functional/Dropdown.php +++ b/tests/functional/Dropdown.php @@ -1921,8 +1921,9 @@ public function testClone($dropdown_class) $input['items_id'] = 1; } $this->integer($original_items_id = $item->add($input))->isGreaterThan(0); + $original_fields = $item->fields; $this->integer($item->clone())->isNotEqualTo($original_items_id); - foreach ($input as $field => $value) { + foreach ($original_fields as $field => $value) { $this->variable($item->fields[$field])->isEqualTo($value); } } From 770ef3b4aecb38d320a00f012bfa432b73664461 Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Thu, 22 Feb 2024 11:01:04 -0500 Subject: [PATCH 19/38] update hlapi schema for state --- src/Api/HL/Controller/DropdownController.php | 87 +++++++++++++++---- src/Api/HL/Controller/ReportController.php | 12 +-- src/Api/HL/Doc/Schema.php | 18 ++++ src/Api/HL/GraphQL.php | 1 + src/Api/HL/GraphQLGenerator.php | 3 - src/Api/HL/Search.php | 27 ++++-- .../Api/HL/Controller/GraphQLController.php | 53 +++++++++++ 7 files changed, 161 insertions(+), 40 deletions(-) diff --git a/src/Api/HL/Controller/DropdownController.php b/src/Api/HL/Controller/DropdownController.php index fb2039a2365..b6b05ac052f 100644 --- a/src/Api/HL/Controller/DropdownController.php +++ b/src/Api/HL/Controller/DropdownController.php @@ -129,30 +129,79 @@ protected static function getRawKnownSchemas(): array 'is_recursive' => ['type' => Doc\Schema::TYPE_BOOLEAN], 'parent' => self::getDropdownTypeSchema(class: State::class, full_schema: 'State'), 'level' => ['type' => Doc\Schema::TYPE_INTEGER], - 'is_visible_computer' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_monitor' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_network_equipment' => ['x-field' => 'is_visible_networkequipment','type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_peripheral' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_phone' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_printer' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_software_version' => ['x-field' => 'is_visible_softwareversion','type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_software_license' => ['x-field' => 'is_visible_softwarelicense','type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_line' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_certificate' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_rack' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_passive_dcequipment' => ['x-field' => 'is_visible_passivedcequipment', 'type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_enclosure' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_pdu' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_cluster' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_contract' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_appliance' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_cable' => ['type' => Doc\Schema::TYPE_BOOLEAN], - 'is_visible_database_instance' => ['x-field' => 'is_visible_databaseinstance', 'type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_computer' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_monitor' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_network_equipment' => ['x-field' => 'is_visible_networkequipment','type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_peripheral' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_phone' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_printer' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_software_version' => ['x-field' => 'is_visible_softwareversion','type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_software_license' => ['x-field' => 'is_visible_softwarelicense','type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_line' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_certificate' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_rack' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_passive_dcequipment' => ['x-field' => 'is_visible_passivedcequipment', 'type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_enclosure' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_pdu' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_cluster' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_contract' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_appliance' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_cable' => ['type' => Doc\Schema::TYPE_BOOLEAN], +// 'is_visible_database_instance' => ['x-field' => 'is_visible_databaseinstance', 'type' => Doc\Schema::TYPE_BOOLEAN], 'is_visible_helpdesk' => ['x-field' => 'is_helpdesk_visible', 'type' => Doc\Schema::TYPE_BOOLEAN], 'date_creation' => ['type' => Doc\Schema::TYPE_STRING, 'format' => Doc\Schema::FORMAT_STRING_DATE_TIME], 'date_mod' => ['type' => Doc\Schema::TYPE_STRING, 'format' => Doc\Schema::FORMAT_STRING_DATE_TIME], ] ]; + $visiblities = [ + 'computer', + 'monitor', + 'networkequipment', + 'peripheral', + 'phone', + 'printer', + 'softwareversion', + 'softwarelicense', + 'line', + 'certificate', + 'rack', + 'passivedcequipment', + 'enclosure', + 'pdu', + 'cluster', + 'contract', + 'appliance', + 'databaseinstance', + 'cable', + 'unmanaged' + ]; + + $schemas['State_Visibilities'] = [ + 'type' => Doc\Schema::TYPE_OBJECT, + 'properties' => [] + ]; + $schemas['State']['properties']['visibilities'] = [ + 'type' => Doc\Schema::TYPE_OBJECT, + 'x-full-schema' => 'State_Visibilities', + ]; + + foreach ($visiblities as $visiblity) { + $schemas['State_Visibilities']['properties'][$visiblity] = [ + 'type' => Doc\Schema::TYPE_BOOLEAN, + 'x-field' => 'is_visible', + 'x-readonly' => true, + 'x-join' => [ + 'table' => \DropdownVisibility::getTable(), + 'fkey' => 'id', + 'field' => 'items_id', + 'condition' => [ + 'itemtype' => 'State', + 'visible_itemtype' => $visiblity + ] + ] + ]; + } + $schemas['State']['properties']['visibilities']['properties'] = $schemas['State_Visibilities']['properties']; $schemas['Manufacturer'] = [ 'type' => Doc\Schema::TYPE_OBJECT, diff --git a/src/Api/HL/Controller/ReportController.php b/src/Api/HL/Controller/ReportController.php index b850861a49e..dbe3d2d7ab1 100644 --- a/src/Api/HL/Controller/ReportController.php +++ b/src/Api/HL/Controller/ReportController.php @@ -241,18 +241,8 @@ protected static function getRawKnownSchemas(): array 'name' => [ 'type' => Doc\Schema::TYPE_STRING, ], - 'entity' => [ - 'type' => Doc\Schema::TYPE_OBJECT, + 'entity' => self::getDropdownTypeSchema(class: \Entity::class, full_schema: 'Entity') + [ 'description' => 'The entity the item belongs to', - 'properties' => [ - 'id' => [ - 'type' => Doc\Schema::TYPE_INTEGER, - 'format' => Doc\Schema::FORMAT_INTEGER_INT64, - ], - 'name' => [ - 'type' => Doc\Schema::TYPE_STRING, - ], - ] ], 'is_deleted' => [ 'type' => Doc\Schema::TYPE_BOOLEAN, diff --git a/src/Api/HL/Doc/Schema.php b/src/Api/HL/Doc/Schema.php index 9bb804b4c1c..164d694b119 100644 --- a/src/Api/HL/Doc/Schema.php +++ b/src/Api/HL/Doc/Schema.php @@ -265,6 +265,24 @@ public static function getJoins(array $props, string $prefix = '', ?array $paren } } } + if ($prefix === '') { + // Fix parent_join for all joins + foreach ($joins as $join_name => $join) { + if (isset($join['join_parent'])) { + // This join is supposed to have a parent + // The set parent may not be correct currently. The join's parent may in fact be an ancestor of the one set + // We need to check if the current parent exists in the list of joins. If not, we need to find the correct parent by walking up the tree + $parent = $join['join_parent']; + while ($parent !== '') { + if (isset($joins[$parent])) { + $joins[$join_name]['join_parent'] = $parent; + break; + } + $parent = substr($parent, 0, strrpos($parent, chr(0x1F))); + } + } + } + } return $joins; } diff --git a/src/Api/HL/GraphQL.php b/src/Api/HL/GraphQL.php index 4e62ad9bc29..3e76e75f1a3 100644 --- a/src/Api/HL/GraphQL.php +++ b/src/Api/HL/GraphQL.php @@ -84,6 +84,7 @@ public static function processRequest(Request $request): array } ); } catch (\Throwable $e) { + trigger_error("Error processing GraphQL request: {$e->getMessage()}", E_USER_WARNING); return []; } return $result->toArray(); diff --git a/src/Api/HL/GraphQLGenerator.php b/src/Api/HL/GraphQLGenerator.php index cd18d7e17fb..ec957bb2a72 100644 --- a/src/Api/HL/GraphQLGenerator.php +++ b/src/Api/HL/GraphQLGenerator.php @@ -93,9 +93,6 @@ private function loadTypes() { $component_schemas = OpenAPIGenerator::getComponentSchemas(); foreach ($component_schemas as $schema_name => $schema) { - if (!isset($schema['x-itemtype'])) { - continue; - } $new_types = $this->getTypesForSchema($schema_name, $schema); foreach ($new_types as $type_name => $type) { $this->types[$type_name] = $type; diff --git a/src/Api/HL/Search.php b/src/Api/HL/Search.php index fa0b5296cf7..ed3f2431107 100644 --- a/src/Api/HL/Search.php +++ b/src/Api/HL/Search.php @@ -200,8 +200,7 @@ private function getSelectCriteriaForProperty(string $prop_name, bool $distinct_ $sql_field = $this->getSQLFieldForProperty($prop_name); $expression = $this->db_read::quoteName($sql_field); if (str_contains($sql_field, '.')) { - $join_name = substr($sql_field, 0, strrpos($sql_field, '.')); - $join_name = str_replace(chr(0x1F), '.', $join_name); + $join_name = $this->getJoinNameForProperty($prop_name); // Check if the join property is in an array. If so, we need to concat each result. if (array_key_exists($join_name, $this->joins)) { $join_def = $this->joins[$join_name]; @@ -577,6 +576,17 @@ static function ($prop_name) use ($primary_key, $join) { throw new RuntimeException("Cannot find primary key property for join $join"); } + private function getJoinNameForProperty(string $prop_name): string + { + if (array_key_exists(str_replace(chr(0x1F), '.', $prop_name), $this->joins)) { + $join_name = str_replace(chr(0x1F), '.', $prop_name); + } else { + $join_name = substr($prop_name, 0, strrpos($prop_name, chr(0x1F))); + $join_name = str_replace(chr(0x1F), '.', $join_name); + } + return $join_name; + } + /** * @return array Matching records in the format Itemtype => IDs * @phpstan-return array @@ -796,8 +806,10 @@ private function assembleHydratedRecords(array $dehydrated_row, string $schema_n } } else { // Add the joined item fields - $join_name = substr($dehydrated_ref, 0, strrpos($dehydrated_ref, chr(0x1F))); - $join_name = str_replace(chr(0x1F), '.', $join_name); + $join_name = $this->getJoinNameForProperty($dehydrated_ref); + if (isset($this->flattened_properties[$join_name])) { + continue; + } if (!ArrayPathAccessor::hasElementByArrayPath($hydrated_record, $join_name)) { ArrayPathAccessor::setElementByArrayPath($hydrated_record, $join_name, []); } @@ -824,7 +836,9 @@ private function assembleHydratedRecords(array $dehydrated_row, string $schema_n // Do this last as some scalar joined properties may be nested and have other data added after the main record was built foreach ($dehydrated_row as $k => $v) { $normalized_k = str_replace(chr(0x1F), '.', $k); - if (isset($this->joins[$normalized_k]) && !isset($hydrated_record[$normalized_k])) { + if (isset($this->joins[$normalized_k]) && !ArrayPathAccessor::hasElementByArrayPath($hydrated_record, $normalized_k)) { + $v = explode(chr(0x1E), $v); + $v = end($v); ArrayPathAccessor::setElementByArrayPath($hydrated_record, $normalized_k, $v); } } @@ -948,8 +962,7 @@ private function hydrateRecords(array $records): array $criteria['SELECT'][] = new QueryExpression($this->db_read::quoteValue($schema_name), '_itemtype'); } } else { - $join_name = substr($fkey, 0, strrpos($fkey, chr(0x1F))); - $join_name = str_replace(chr(0x1F), '.', $join_name); + $join_name = $this->getJoinNameForProperty($fkey); $props_to_use = array_filter($this->flattened_properties, function ($prop_name) use ($join_name) { if (isset($this->joins[$prop_name])) { /** Scalar joined properties are fetched directly during {@link self::getMatchingRecords()} */ diff --git a/tests/functional/Glpi/Api/HL/Controller/GraphQLController.php b/tests/functional/Glpi/Api/HL/Controller/GraphQLController.php index 100a5b1bfae..40668cf5a3a 100644 --- a/tests/functional/Glpi/Api/HL/Controller/GraphQLController.php +++ b/tests/functional/Glpi/Api/HL/Controller/GraphQLController.php @@ -195,4 +195,57 @@ public function testFullSchemaReplacement() }); }); } + + /** + * Tests a case where there are scalar joins inside an already-joined field (status in this case). + * @return void + */ + public function testGetStateVisibilities() + { + $state = new \State(); + $this->integer($states_id = $state->add([ + 'name' => __FUNCTION__, + 'entities_id' => getItemByTypeName('Entity', '_test_root_entity', true), + 'is_visible_computer' => 1, + 'is_visible_monitor' => 0 + ]))->isGreaterThan(0); + $computer = new \Computer(); + $this->integer($computers_id = $computer->add([ + 'name' => __FUNCTION__, + 'entities_id' => getItemByTypeName('Entity', '_test_root_entity', true), + 'states_id' => $states_id + ]))->isGreaterThan(0); + + $this->login(); + $request = new Request('POST', '/GraphQL', [], <<api->call($request, function ($call) { + /** @var \HLAPICallAsserter $call */ + $call->response + ->status(fn ($status) => $this->integer($status)->isEqualTo(200)) + ->jsonContent(function ($content) { + $this->array($content['data'])->hasSize(1); + $this->array($content['data']['Computer'])->hasSize(1); + $this->array($content['data']['Computer'][0])->hasKey('id'); + $this->array($content['data']['Computer'][0])->hasKey('name'); + $this->array($content['data']['Computer'][0])->hasKey('status'); + $this->array($content['data']['Computer'][0]['status'])->hasKey('name'); + $this->boolean($content['data']['Computer'][0]['status']['visibilities']['computer'])->isTrue(); + $this->boolean($content['data']['Computer'][0]['status']['visibilities']['monitor'])->isFalse(); + }); + }); + } } From 26788c81fc10bb8a4a3fb962b0a9b15380dde758 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 23 Feb 2024 08:56:40 +0100 Subject: [PATCH 20/38] Cleanup, use cfg_glpi --- src/Api/HL/Controller/DropdownController.php | 45 ++------------------ 1 file changed, 4 insertions(+), 41 deletions(-) diff --git a/src/Api/HL/Controller/DropdownController.php b/src/Api/HL/Controller/DropdownController.php index b6b05ac052f..ad39c74c390 100644 --- a/src/Api/HL/Controller/DropdownController.php +++ b/src/Api/HL/Controller/DropdownController.php @@ -76,6 +76,9 @@ final class DropdownController extends AbstractController protected static function getRawKnownSchemas(): array { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + $schemas = []; $schemas['Location'] = [ @@ -129,52 +132,12 @@ protected static function getRawKnownSchemas(): array 'is_recursive' => ['type' => Doc\Schema::TYPE_BOOLEAN], 'parent' => self::getDropdownTypeSchema(class: State::class, full_schema: 'State'), 'level' => ['type' => Doc\Schema::TYPE_INTEGER], -// 'is_visible_computer' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_monitor' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_network_equipment' => ['x-field' => 'is_visible_networkequipment','type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_peripheral' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_phone' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_printer' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_software_version' => ['x-field' => 'is_visible_softwareversion','type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_software_license' => ['x-field' => 'is_visible_softwarelicense','type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_line' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_certificate' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_rack' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_passive_dcequipment' => ['x-field' => 'is_visible_passivedcequipment', 'type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_enclosure' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_pdu' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_cluster' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_contract' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_appliance' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_cable' => ['type' => Doc\Schema::TYPE_BOOLEAN], -// 'is_visible_database_instance' => ['x-field' => 'is_visible_databaseinstance', 'type' => Doc\Schema::TYPE_BOOLEAN], 'is_visible_helpdesk' => ['x-field' => 'is_helpdesk_visible', 'type' => Doc\Schema::TYPE_BOOLEAN], 'date_creation' => ['type' => Doc\Schema::TYPE_STRING, 'format' => Doc\Schema::FORMAT_STRING_DATE_TIME], 'date_mod' => ['type' => Doc\Schema::TYPE_STRING, 'format' => Doc\Schema::FORMAT_STRING_DATE_TIME], ] ]; - $visiblities = [ - 'computer', - 'monitor', - 'networkequipment', - 'peripheral', - 'phone', - 'printer', - 'softwareversion', - 'softwarelicense', - 'line', - 'certificate', - 'rack', - 'passivedcequipment', - 'enclosure', - 'pdu', - 'cluster', - 'contract', - 'appliance', - 'databaseinstance', - 'cable', - 'unmanaged' - ]; + $visiblities = array_map('strtolower', $CFG_GLPI['state_types']); $schemas['State_Visibilities'] = [ 'type' => Doc\Schema::TYPE_OBJECT, From 9472233834fc902bb049549219619eacbd48e5f6 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 23 Feb 2024 09:50:01 +0100 Subject: [PATCH 21/38] Replace is_visible_* on all objects --- src/Appliance.php | 4 ++-- src/Cable.php | 4 ++-- src/Certificate.php | 4 ++-- src/Cluster.php | 4 ++-- src/Contract.php | 4 ++-- src/Enclosure.php | 4 ++-- src/Line.php | 4 ++-- src/Monitor.php | 4 ++-- src/NetworkEquipment.php | 4 ++-- src/PDU.php | 4 ++-- src/PassiveDCEquipment.php | 4 ++-- src/Peripheral.php | 4 ++-- src/Phone.php | 4 ++-- src/Printer.php | 4 ++-- src/Rack.php | 4 ++-- src/SoftwareLicense.php | 4 ++-- src/SoftwareVersion.php | 14 +++++++------- src/Unmanaged.php | 4 ++-- 18 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/Appliance.php b/src/Appliance.php index be8e28b63a5..0f08d70c94e 100644 --- a/src/Appliance.php +++ b/src/Appliance.php @@ -292,11 +292,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '32', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_appliance' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab = array_merge($tab, Certificate::rawSearchOptionsToAdd()); diff --git a/src/Cable.php b/src/Cable.php index f1d08929446..3abc12462bd 100644 --- a/src/Cable.php +++ b/src/Cable.php @@ -300,11 +300,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_cable' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Certificate.php b/src/Certificate.php index 234b25516fe..68e01a1b4a3 100644 --- a/src/Certificate.php +++ b/src/Certificate.php @@ -257,11 +257,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_certificate' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Cluster.php b/src/Cluster.php index 274c0cb7135..4954a3e6810 100644 --- a/src/Cluster.php +++ b/src/Cluster.php @@ -91,11 +91,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_cluster' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Contract.php b/src/Contract.php index 042569ca6c6..04c393215aa 100644 --- a/src/Contract.php +++ b/src/Contract.php @@ -514,11 +514,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_contract' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Enclosure.php b/src/Enclosure.php index 99041d4343b..e75a80f5bb7 100644 --- a/src/Enclosure.php +++ b/src/Enclosure.php @@ -127,11 +127,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_enclosure' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Line.php b/src/Line.php index 10a7b6343a1..13602ce9d0e 100644 --- a/src/Line.php +++ b/src/Line.php @@ -148,11 +148,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_line' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Monitor.php b/src/Monitor.php index 218b2d5af8b..2f7e1f23392 100644 --- a/src/Monitor.php +++ b/src/Monitor.php @@ -234,11 +234,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_monitor' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/NetworkEquipment.php b/src/NetworkEquipment.php index 10276b0afa9..b2c1b3005a9 100644 --- a/src/NetworkEquipment.php +++ b/src/NetworkEquipment.php @@ -298,11 +298,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_networkequipment' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/PDU.php b/src/PDU.php index 6f4a8e35047..1aab8b2cfe9 100644 --- a/src/PDU.php +++ b/src/PDU.php @@ -146,11 +146,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_pdu' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/PassiveDCEquipment.php b/src/PassiveDCEquipment.php index 9c97a93a89b..3e584f757cf 100644 --- a/src/PassiveDCEquipment.php +++ b/src/PassiveDCEquipment.php @@ -143,11 +143,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_passivedcequipment' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Peripheral.php b/src/Peripheral.php index ed10141b362..b5a8b896c04 100644 --- a/src/Peripheral.php +++ b/src/Peripheral.php @@ -219,11 +219,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_peripheral' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Phone.php b/src/Phone.php index 125967daed0..c9f4e0a69c2 100644 --- a/src/Phone.php +++ b/src/Phone.php @@ -257,11 +257,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_phone' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Printer.php b/src/Printer.php index af54cdd4d12..02860ec04c8 100644 --- a/src/Printer.php +++ b/src/Printer.php @@ -381,11 +381,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_printer' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Rack.php b/src/Rack.php index 39f8aa58cb2..ad6f2de981e 100644 --- a/src/Rack.php +++ b/src/Rack.php @@ -178,11 +178,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_rack' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/SoftwareLicense.php b/src/SoftwareLicense.php index 40a8fe275fb..83082063a99 100644 --- a/src/SoftwareLicense.php +++ b/src/SoftwareLicense.php @@ -500,11 +500,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_softwarelicense' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/SoftwareVersion.php b/src/SoftwareVersion.php index 0d6a3114447..e5c76fbd2a3 100644 --- a/src/SoftwareVersion.php +++ b/src/SoftwareVersion.php @@ -148,7 +148,7 @@ public function showForm($ID, array $options = []) echo "" . __('Status') . ""; State::dropdown(['value' => $this->fields["states_id"], 'entity' => $this->fields["entities_id"], - 'condition' => ['is_visible_softwareversion' => 1] + 'condition' => self::getStateVisibilityCriteria() ]); echo "\n"; @@ -201,11 +201,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_softwareversion' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; $tab[] = [ @@ -261,10 +261,10 @@ public static function dropdownForOneSoftware($options = []) 'DISTINCT' => true, 'FROM' => 'glpi_softwareversions', 'LEFT JOIN' => [ - 'glpi_states' => [ + State::getTable() => [ 'ON' => [ 'glpi_softwareversions' => 'states_id', - 'glpi_states' => 'id' + State::getTable() => 'id' ] ] ], @@ -332,10 +332,10 @@ public static function showForSoftware(Software $soft) ], 'FROM' => 'glpi_softwareversions', 'LEFT JOIN' => [ - 'glpi_states' => [ + State::getTable() => [ 'ON' => [ 'glpi_softwareversions' => 'states_id', - 'glpi_states' => 'id' + State::getTable() => 'id' ] ] ], diff --git a/src/Unmanaged.php b/src/Unmanaged.php index c7fc4dc68d8..7e8d262b00f 100644 --- a/src/Unmanaged.php +++ b/src/Unmanaged.php @@ -187,11 +187,11 @@ public function rawSearchOptions() $tab[] = [ 'id' => '31', - 'table' => 'glpi_states', + 'table' => State::getTable(), 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => ['is_visible_unmanaged' => 1] + 'condition' => self::getStateVisibilityCriteria() ]; return $tab; From b7f17c12bce72913538248036196084d84e9b8c0 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 23 Feb 2024 11:01:21 +0100 Subject: [PATCH 22/38] Fix test --- tests/functional/Search.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/functional/Search.php b/tests/functional/Search.php index f84d08498ce..07c5f7141f9 100644 --- a/tests/functional/Search.php +++ b/tests/functional/Search.php @@ -2296,6 +2296,9 @@ public function testSearchAllAssets() public function testSearchWithNamespacedItem() { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + $search_params = [ 'is_deleted' => 0, 'start' => 0, @@ -2304,6 +2307,7 @@ public function testSearchWithNamespacedItem() $this->login(); $this->setEntity('_test_root_entity', true); + $CFG_GLPI['state_types'][] = 'SearchTest\\Computer'; $data = $this->doSearch('SearchTest\\Computer', $search_params); $this->string($data['sql']['search']) From f492e337f6b6f5cb5056046bafa9d4013edaa857 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 23 Feb 2024 11:01:35 +0100 Subject: [PATCH 23/38] is_visible_* no longer exists --- src/Inventory/Conf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Inventory/Conf.php b/src/Inventory/Conf.php index 6e5b9370a84..83ee53609b4 100644 --- a/src/Inventory/Conf.php +++ b/src/Inventory/Conf.php @@ -952,7 +952,7 @@ function changestatus() { echo ""; $condition = []; foreach ($CFG_GLPI['inventory_types'] as $inv_type) { - $condition['is_visible_' . strtolower($inv_type)] = 1; + $condition[] = $int_type::getStateVisibilityCriteria(); } From 48156cd79d0ac3c76957eee176d6b8e35171b935 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 23 Feb 2024 14:55:30 +0100 Subject: [PATCH 24/38] Fix typo --- src/Inventory/Conf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Inventory/Conf.php b/src/Inventory/Conf.php index 83ee53609b4..0d36d1e3f3c 100644 --- a/src/Inventory/Conf.php +++ b/src/Inventory/Conf.php @@ -952,7 +952,7 @@ function changestatus() { echo ""; $condition = []; foreach ($CFG_GLPI['inventory_types'] as $inv_type) { - $condition[] = $int_type::getStateVisibilityCriteria(); + $condition[] = $inv_type::getStateVisibilityCriteria(); } From b9e7aef47ae725f9ea175169ba230c653ec71b23 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 23 Feb 2024 15:39:05 +0100 Subject: [PATCH 25/38] is_visible_* ahs been removed; try with new version --- src/State.php | 234 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 180 insertions(+), 54 deletions(-) diff --git a/src/State.php b/src/State.php index de0b1b57f3e..d46f3b678ca 100644 --- a/src/State.php +++ b/src/State.php @@ -377,22 +377,36 @@ public function rawSearchOptions() $tab[] = [ 'id' => '21', - 'table' => $this->getTable(), - 'field' => 'is_visible_computer', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf(__('%1$s - %2$s'), __('Visibility'), Computer::getTypeName(Session::getPluralNumber())), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Computer' + ] + ] ]; $tab[] = [ 'id' => '22', - 'table' => $this->getTable(), - 'field' => 'is_visible_softwareversion', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), SoftwareVersion::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'SoftwareVersion' + ] + ] ]; $tab[] = [ @@ -412,182 +426,294 @@ public function rawSearchOptions() $tab[] = [ 'id' => '24', - 'table' => $this->getTable(), - 'field' => 'is_visible_printer', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf(__('%1$s - %2$s'), __('Visibility'), Printer::getTypeName(Session::getPluralNumber())), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Printer' + ] + ] ]; $tab[] = [ 'id' => '25', - 'table' => $this->getTable(), - 'field' => 'is_visible_peripheral', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf(__('%1$s - %2$s'), __('Visibility'), Peripheral::getTypeName(Session::getPluralNumber())), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Peripheral' + ] + ] ]; $tab[] = [ 'id' => '26', - 'table' => $this->getTable(), - 'field' => 'is_visible_phone', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf(__('%1$s - %2$s'), __('Visibility'), Phone::getTypeName(Session::getPluralNumber())), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Phone' + ] + ] ]; $tab[] = [ 'id' => '27', - 'table' => $this->getTable(), - 'field' => 'is_visible_networkequipment', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), NetworkEquipment::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'NetworkEquipment' + ] + ] ]; $tab[] = [ 'id' => '28', - 'table' => $this->getTable(), - 'field' => 'is_visible_softwarelicense', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), SoftwareLicense::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'SoftwareLicense' + ] + ] ]; $tab[] = [ 'id' => '29', - 'table' => $this->getTable(), - 'field' => 'is_visible_certificate', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), Certificate::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Certificate' + ] + ] ]; $tab[] = [ 'id' => '30', - 'table' => $this->getTable(), - 'field' => 'is_visible_rack', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), Rack::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Rack' + ] + ] ]; $tab[] = [ 'id' => '31', - 'table' => $this->getTable(), - 'field' => 'is_visible_line', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), Line::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Line' + ] + ] ]; $tab[] = [ 'id' => '32', - 'table' => $this->getTable(), - 'field' => 'is_visible_enclosure', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), Enclosure::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Enclosure' + ] + ] ]; $tab[] = [ 'id' => '33', - 'table' => $this->getTable(), - 'field' => 'is_visible_pdu', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), PDU::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'PDU' + ] + ] ]; $tab[] = [ 'id' => '34', - 'table' => $this->getTable(), - 'field' => 'is_visible_cluster', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), Cluster::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Cluster' + ] + ] ]; $tab[] = [ 'id' => '35', - 'table' => $this->getTable(), - 'field' => 'is_visible_passivedcequipment', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), PassiveDCEquipment::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'PassiveDCEquipment' + ] + ] ]; $tab[] = [ 'id' => '36', - 'table' => $this->getTable(), - 'field' => 'is_visible_contract', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), Contract::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Contract' + ] + ] ]; $tab[] = [ 'id' => '37', - 'table' => $this->getTable(), - 'field' => 'is_visible_appliance', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), Appliance::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Appliance' + ] + ] ]; $tab[] = [ 'id' => '38', - 'table' => $this->getTable(), - 'field' => 'is_visible_cable', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), Cable::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'Cable' + ] + ] ]; $tab[] = [ 'id' => '39', - 'table' => $this->getTable(), - 'field' => 'is_visible_databaseinstance', + 'table' => DropdownVisibility::getTable(), + 'field' => 'is_visible', 'name' => sprintf( __('%1$s - %2$s'), __('Visibility'), DatabaseInstance::getTypeName(Session::getPluralNumber()) ), - 'datatype' => 'bool' + 'datatype' => 'bool', + 'joinparams' => [ + 'jointype' => 'itemtypeonly', + 'table' => $this->getTable(), + 'condition' => [ + 'NEWTABLE.visible_itemtype' => 'DatabaseInstance' + ] + ] ]; $tab[] = [ From aa728523f386131f635373b50940c8286a00944d Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Fri, 23 Feb 2024 16:19:38 +0100 Subject: [PATCH 26/38] Make search work in State (thanks to Curtis!) --- src/State.php | 57 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/State.php b/src/State.php index d46f3b678ca..41fdc22b480 100644 --- a/src/State.php +++ b/src/State.php @@ -385,7 +385,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Computer' + 'NEWTABLE.visible_itemtype' => 'Computer', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -404,7 +405,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'SoftwareVersion' + 'NEWTABLE.visible_itemtype' => 'SoftwareVersion', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -419,7 +421,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Monitor' + 'NEWTABLE.visible_itemtype' => 'Monitor', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -434,7 +437,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Printer' + 'NEWTABLE.visible_itemtype' => 'Printer', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -449,7 +453,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Peripheral' + 'NEWTABLE.visible_itemtype' => 'Peripheral', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -464,7 +469,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Phone' + 'NEWTABLE.visible_itemtype' => 'Phone', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -483,7 +489,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'NetworkEquipment' + 'NEWTABLE.visible_itemtype' => 'NetworkEquipment', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -502,7 +509,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'SoftwareLicense' + 'NEWTABLE.visible_itemtype' => 'SoftwareLicense', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -521,7 +529,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Certificate' + 'NEWTABLE.visible_itemtype' => 'Certificate', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -540,7 +549,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Rack' + 'NEWTABLE.visible_itemtype' => 'Rack', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -559,7 +569,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Line' + 'NEWTABLE.visible_itemtype' => 'Line', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -578,7 +589,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Enclosure' + 'NEWTABLE.visible_itemtype' => 'Enclosure', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -597,7 +609,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'PDU' + 'NEWTABLE.visible_itemtype' => 'PDU', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -616,7 +629,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Cluster' + 'NEWTABLE.visible_itemtype' => 'Cluster', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -635,7 +649,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'PassiveDCEquipment' + 'NEWTABLE.visible_itemtype' => 'PassiveDCEquipment', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -654,7 +669,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Contract' + 'NEWTABLE.visible_itemtype' => 'Contract', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -673,7 +689,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Appliance' + 'NEWTABLE.visible_itemtype' => 'Appliance', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -692,7 +709,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'Cable' + 'NEWTABLE.visible_itemtype' => 'Cable', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; @@ -711,7 +729,8 @@ public function rawSearchOptions() 'jointype' => 'itemtypeonly', 'table' => $this->getTable(), 'condition' => [ - 'NEWTABLE.visible_itemtype' => 'DatabaseInstance' + 'NEWTABLE.visible_itemtype' => 'DatabaseInstance', + 'NEWTABLE.items_id' => new QueryExpression('REFTABLE.id') ] ] ]; From 2d7bf49d863e0f37cb0654191dca4ff633f36184 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Mon, 26 Feb 2024 09:21:09 +0100 Subject: [PATCH 27/38] Revert ""Improve" FKEY condition detection" This reverts commit e804812fd04f9e49e8da0580acb84dd5de8b3002. --- src/DBmysqlIterator.php | 15 ++------- src/Features/State.php | 2 +- src/Search/Provider/SQLProvider.php | 4 +-- tests/units/DBmysqlIterator.php | 47 +---------------------------- 4 files changed, 6 insertions(+), 62 deletions(-) diff --git a/src/DBmysqlIterator.php b/src/DBmysqlIterator.php index 9fb693d82ad..19380971f4a 100644 --- a/src/DBmysqlIterator.php +++ b/src/DBmysqlIterator.php @@ -725,19 +725,8 @@ private function analyseFkey($values) (is_numeric($t2) ? DBmysql::quoteName($f2) : DBmysql::quoteName($t2) . '.' . DBmysql::quoteName($f2)); } } else if (count($values) == 3) { - $real_values = []; - foreach ($values as $k => $v) { - if (is_string($k)) { - $real_values[$k] = $v; - } else { - $condition = $v; - } - } - if (count($real_values) != 2 || !isset($condition)) { - throw new \LogicException('BAD FOREIGN KEY, should be [ table1 => key1, table2 => key2 ] or [ table1 => key1, table2 => key2, [criteria]].'); - } - //$condition = array_pop($real_values); - $fkey = $this->analyseFkey($real_values); + $condition = array_pop($values); + $fkey = $this->analyseFkey($values); $condition_value = $this->analyseCrit(current($condition)); if (!empty(trim($condition_value))) { return $fkey . ' ' . key($condition) . ' ' . $condition_value; diff --git a/src/Features/State.php b/src/Features/State.php index d2b728d77bc..139d457b922 100644 --- a/src/Features/State.php +++ b/src/Features/State.php @@ -102,7 +102,7 @@ public function getStateVisibilityCriteria(): array \DropdownVisibility::getTable() => [ 'ON' => [ \DropdownVisibility::getTable() => 'items_id', - \State::getTable() => 'id', [ + \State::getTable() => 'id', 'zzz' => [ 'AND' => [ \DropdownVisibility::getTable() . '.itemtype' => \State::getType() ] diff --git a/src/Search/Provider/SQLProvider.php b/src/Search/Provider/SQLProvider.php index b29d41d1ea0..dfbe908ee70 100644 --- a/src/Search/Provider/SQLProvider.php +++ b/src/Search/Provider/SQLProvider.php @@ -2652,7 +2652,7 @@ public static function getLeftJoinCriteria( "$new_table$AS" => [ 'ON' => [ $nt => 'itemtype', - 'qexp' => new QueryExpression("'$used_itemtype'"), + new QueryExpression("'$used_itemtype'"), ] ] ] @@ -3169,7 +3169,7 @@ public static function getDropdownTranslationJoinCriteria($alias, $table, $itemt "glpi_dropdowntranslations AS $alias" => [ 'ON' => [ $alias => 'itemtype', - 'qexp' => new QueryExpression("'$itemtype'"), + new QueryExpression("'$itemtype'"), [ 'AND' => [ "$alias.items_id" => "$table.id", diff --git a/tests/units/DBmysqlIterator.php b/tests/units/DBmysqlIterator.php index 00ca0cae76e..44f7e3e2593 100644 --- a/tests/units/DBmysqlIterator.php +++ b/tests/units/DBmysqlIterator.php @@ -480,52 +480,7 @@ function () { 'SELECT * FROM `foo` LEFT JOIN `bar` ON (`bar`.`id` = `foo`.`fk` AND `field` = \'42\')' ); - //order in fkey should not matter - $it = $this->it->execute( - 'foo', - [ - 'LEFT JOIN' => [ - 'bar' => [ - 'FKEY' => [ - [ - 'AND' => ['field' => 42] - ], - 'bar' => 'id', - 'foo' => 'fk' - ] - ] - ] - ] - ); - $this->string($it->getSql())->isIdenticalTo( - 'SELECT * FROM `foo` LEFT JOIN `bar` ON (`bar`.`id` = `foo`.`fk` AND `field` = \'42\')' - ); - - //fail with condition set as associative array - $this->exception( - function () { - $it = $this->it->execute( - 'foo', - [ - 'LEFT JOIN' => [ - 'bar' => [ - 'FKEY' => [ - 'bar' => 'id', - 'foo' => 'fk', - 'zzz' => [ - 'AND' => ['field' => 42] - ] - ] - ] - ] - ] - ); - } - ) - ->isInstanceOf('LogicException') - ->hasMessage('BAD FOREIGN KEY, should be [ table1 => key1, table2 => key2 ] or [ table1 => key1, table2 => key2, [criteria]].'); - - //test derived table in JOIN statement + //test derived table in JOIN statement $it = $this->it->execute( 'foo', [ From df8746c203690154c03c8ed5536aa3ac683b736b Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Mon, 26 Feb 2024 09:21:42 +0100 Subject: [PATCH 28/38] Revert "Fix condition \\o//" This reverts commit 7a3732b5f714b1c0d93369e089e8ebcbc0430e80. --- src/Features/State.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/State.php b/src/Features/State.php index 139d457b922..d2b728d77bc 100644 --- a/src/Features/State.php +++ b/src/Features/State.php @@ -102,7 +102,7 @@ public function getStateVisibilityCriteria(): array \DropdownVisibility::getTable() => [ 'ON' => [ \DropdownVisibility::getTable() => 'items_id', - \State::getTable() => 'id', 'zzz' => [ + \State::getTable() => 'id', [ 'AND' => [ \DropdownVisibility::getTable() . '.itemtype' => \State::getType() ] From 145225d4ce242a08ae3bf064a14541ddf38b7b2e Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Mon, 26 Feb 2024 09:39:53 +0100 Subject: [PATCH 29/38] Test a better solution for FKEY condition detection --- src/DBmysqlIterator.php | 17 +++++++++++-- tests/units/DBmysqlIterator.php | 45 ++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/DBmysqlIterator.php b/src/DBmysqlIterator.php index 19380971f4a..70d437ce4fd 100644 --- a/src/DBmysqlIterator.php +++ b/src/DBmysqlIterator.php @@ -725,8 +725,21 @@ private function analyseFkey($values) (is_numeric($t2) ? DBmysql::quoteName($f2) : DBmysql::quoteName($t2) . '.' . DBmysql::quoteName($f2)); } } else if (count($values) == 3) { - $condition = array_pop($values); - $fkey = $this->analyseFkey($values); + $real_values = []; + foreach ($values as $k => $v) { + if (is_array($v)) { + $condition = $v; + } else { + $real_values[$k] = $v; + } + } + + if (!isset($condition)) { + //in theory, should never happen + $condition = array_pop($real_values); + } + + $fkey = $this->analyseFkey($real_values); $condition_value = $this->analyseCrit(current($condition)); if (!empty(trim($condition_value))) { return $fkey . ' ' . key($condition) . ' ' . $condition_value; diff --git a/tests/units/DBmysqlIterator.php b/tests/units/DBmysqlIterator.php index 44f7e3e2593..043a9c3e0be 100644 --- a/tests/units/DBmysqlIterator.php +++ b/tests/units/DBmysqlIterator.php @@ -480,7 +480,50 @@ function () { 'SELECT * FROM `foo` LEFT JOIN `bar` ON (`bar`.`id` = `foo`.`fk` AND `field` = \'42\')' ); - //test derived table in JOIN statement + //order in fkey should not matter + $it = $this->it->execute( + 'foo', + [ + 'LEFT JOIN' => [ + 'bar' => [ + 'FKEY' => [ + [ + 'AND' => ['field' => 42] + ], + 'bar' => 'id', + 'foo' => 'fk' + ] + ] + ] + ] + ); + $this->string($it->getSql())->isIdenticalTo( + 'SELECT * FROM `foo` LEFT JOIN `bar` ON (`bar`.`id` = `foo`.`fk` AND `field` = \'42\')' + ); + + //condition set as associative array should work also + $it = $this->it->execute( + 'foo', + [ + 'LEFT JOIN' => [ + 'bar' => [ + 'FKEY' => [ + 'bar' => 'id', + 'foo' => 'fk', + 'acondition' => [ + 'AND' => ['field' => 42] + ] + ] + ] + ] + ] + ); + $this->string($it->getSql())->isIdenticalTo( + 'SELECT * FROM `foo` LEFT JOIN `bar` ON (`bar`.`id` = `foo`.`fk` AND `field` = \'42\')' + ); + + + //test derived table in JOIN statement $it = $this->it->execute( 'foo', [ From 5fb960bb088579c5991c342662ca3346ea2e307b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Tue, 27 Feb 2024 12:32:08 +0100 Subject: [PATCH 30/38] small fixes --- src/Appliance.php | 2 +- src/Cable.php | 2 +- src/Certificate.php | 2 +- src/Cluster.php | 2 +- src/Computer.php | 2 +- src/Contract.php | 2 +- src/DatabaseInstance.php | 7 ++-- src/DropdownVisibility.php | 3 -- src/Enclosure.php | 2 +- src/Features/State.php | 34 +++++++------------ src/Inventory/Conf.php | 8 +++-- src/Line.php | 2 +- src/Monitor.php | 2 +- src/NetworkEquipment.php | 2 +- src/PDU.php | 2 +- src/PassiveDCEquipment.php | 2 +- src/Peripheral.php | 2 +- src/Phone.php | 2 +- src/Printer.php | 2 +- src/Rack.php | 2 +- src/SoftwareLicense.php | 2 +- src/State.php | 14 ++++---- src/Unmanaged.php | 2 +- .../components/form/item_device.html.twig | 2 +- templates/generic_show_form.html.twig | 2 +- 25 files changed, 49 insertions(+), 57 deletions(-) diff --git a/src/Appliance.php b/src/Appliance.php index 0f08d70c94e..d9af5c66dcd 100644 --- a/src/Appliance.php +++ b/src/Appliance.php @@ -296,7 +296,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab = array_merge($tab, Certificate::rawSearchOptionsToAdd()); diff --git a/src/Cable.php b/src/Cable.php index 3abc12462bd..8a28130dce8 100644 --- a/src/Cable.php +++ b/src/Cable.php @@ -304,7 +304,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Certificate.php b/src/Certificate.php index 68e01a1b4a3..8767db8e4a5 100644 --- a/src/Certificate.php +++ b/src/Certificate.php @@ -261,7 +261,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Cluster.php b/src/Cluster.php index 4954a3e6810..a8f5f176966 100644 --- a/src/Cluster.php +++ b/src/Cluster.php @@ -95,7 +95,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Computer.php b/src/Computer.php index 6b6a7c3a241..552a1e65bc1 100644 --- a/src/Computer.php +++ b/src/Computer.php @@ -425,7 +425,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria(), + 'condition' => $this->getStateVisibilityCriteria(), ]; $tab[] = [ diff --git a/src/Contract.php b/src/Contract.php index 04c393215aa..a01dfbf1bc0 100644 --- a/src/Contract.php +++ b/src/Contract.php @@ -518,7 +518,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/DatabaseInstance.php b/src/DatabaseInstance.php index 1bf381f99f0..529828a6e39 100644 --- a/src/DatabaseInstance.php +++ b/src/DatabaseInstance.php @@ -206,9 +206,10 @@ public function rawSearchOptions() $tab[] = [ 'id' => '41', 'table' => State::getTable(), - 'field' => 'name', - 'name' => _n('State', 'States', 1), - 'datatype' => 'dropdown' + 'field' => 'completename', + 'name' => __('Status'), + 'datatype' => 'dropdown', + 'condition' => $this->getStateVisibilityCriteria(), ]; $tab[] = [ diff --git a/src/DropdownVisibility.php b/src/DropdownVisibility.php index d8d52f6535d..2d23e20cf8d 100644 --- a/src/DropdownVisibility.php +++ b/src/DropdownVisibility.php @@ -33,9 +33,6 @@ * --------------------------------------------------------------------- */ -use Glpi\Application\View\TemplateRenderer; -use Glpi\Dashboard\Widget; - class DropdownVisibility extends CommonDBChild { public static $mustBeAttached = false; //no idea why. diff --git a/src/Enclosure.php b/src/Enclosure.php index e75a80f5bb7..42bb2d82b84 100644 --- a/src/Enclosure.php +++ b/src/Enclosure.php @@ -131,7 +131,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Features/State.php b/src/Features/State.php index d2b728d77bc..ede86e18a26 100644 --- a/src/Features/State.php +++ b/src/Features/State.php @@ -35,17 +35,7 @@ namespace Glpi\Features; -use Agent; -use AutoUpdateSystem; -use CommonDBTM; -use Computer; -use Computer_Item; -use DatabaseInstance; -use Glpi\Inventory\Conf; -use Glpi\Plugin\Hooks; -use Html; -use Plugin; -use RefusedEquipment; +use DropdownVisibility; trait State { @@ -54,16 +44,16 @@ trait State * * @return void */ - protected function checkSetup(): void + private function checkSetup(): void { /** @var array $CFG_GLPI */ global $CFG_GLPI; - if (!in_array(get_class($this), $CFG_GLPI['state_types'])) { + if (!in_array(static::class, $CFG_GLPI['state_types'])) { trigger_error( sprintf( 'Class %s must be present in $CFG_GLPI[\'state_types\']', - get_class($this) + static::class ), E_USER_ERROR ); @@ -80,11 +70,11 @@ protected function checkSetup(): void public function isStateVisible(int $id): bool { $this->checkSetup(); - $dropdownVisibility = new \DropdownVisibility(); + $dropdownVisibility = new DropdownVisibility(); return $dropdownVisibility->getFromDBByCrit([ 'itemtype' => \State::getType(), 'items_id' => $id, - 'visible_itemtype' => get_class($this), + 'visible_itemtype' => static::class, 'is_visible' => 1 ]); } @@ -99,21 +89,21 @@ public function getStateVisibilityCriteria(): array $this->checkSetup(); return [ 'LEFT JOIN' => [ - \DropdownVisibility::getTable() => [ + DropdownVisibility::getTable() => [ 'ON' => [ - \DropdownVisibility::getTable() => 'items_id', + DropdownVisibility::getTable() => 'items_id', \State::getTable() => 'id', [ 'AND' => [ - \DropdownVisibility::getTable() . '.itemtype' => \State::getType() + DropdownVisibility::getTable() . '.itemtype' => \State::getType() ] ] ] ] ], 'WHERE' => [ - \DropdownVisibility::getTable() . '.itemtype' => \State::getType(), - \DropdownVisibility::getTable() . '.visible_itemtype' => get_class($this), - \DropdownVisibility::getTable() . '.is_visible' => 1 + DropdownVisibility::getTable() . '.itemtype' => \State::getType(), + DropdownVisibility::getTable() . '.visible_itemtype' => static::class, + DropdownVisibility::getTable() . '.is_visible' => 1 ] ]; } diff --git a/src/Inventory/Conf.php b/src/Inventory/Conf.php index 0d36d1e3f3c..f4b388fe74c 100644 --- a/src/Inventory/Conf.php +++ b/src/Inventory/Conf.php @@ -952,10 +952,14 @@ function changestatus() { echo ""; $condition = []; foreach ($CFG_GLPI['inventory_types'] as $inv_type) { - $condition[] = $inv_type::getStateVisibilityCriteria(); + if ( + Toolbox::hasTrait($inv_type, \Glpi\Features\State::class) + && $inv_item = getItemForItemtype($inv_type) + ) { + $condition[] = $inv_item->getStateVisibilityCriteria(); + } } - State::dropdown( [ 'name' => 'stale_agents_status_condition[]', diff --git a/src/Line.php b/src/Line.php index 13602ce9d0e..4f87acf893a 100644 --- a/src/Line.php +++ b/src/Line.php @@ -152,7 +152,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Monitor.php b/src/Monitor.php index 2f7e1f23392..ea0d7286bcf 100644 --- a/src/Monitor.php +++ b/src/Monitor.php @@ -238,7 +238,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/NetworkEquipment.php b/src/NetworkEquipment.php index b2c1b3005a9..c582ad99eb1 100644 --- a/src/NetworkEquipment.php +++ b/src/NetworkEquipment.php @@ -302,7 +302,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/PDU.php b/src/PDU.php index 1aab8b2cfe9..9b83e2f79fe 100644 --- a/src/PDU.php +++ b/src/PDU.php @@ -150,7 +150,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/PassiveDCEquipment.php b/src/PassiveDCEquipment.php index 3e584f757cf..017cad90865 100644 --- a/src/PassiveDCEquipment.php +++ b/src/PassiveDCEquipment.php @@ -147,7 +147,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Peripheral.php b/src/Peripheral.php index b5a8b896c04..e561273e469 100644 --- a/src/Peripheral.php +++ b/src/Peripheral.php @@ -223,7 +223,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Phone.php b/src/Phone.php index c9f4e0a69c2..2e912bac9dc 100644 --- a/src/Phone.php +++ b/src/Phone.php @@ -261,7 +261,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Printer.php b/src/Printer.php index 02860ec04c8..efd14629a37 100644 --- a/src/Printer.php +++ b/src/Printer.php @@ -385,7 +385,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/Rack.php b/src/Rack.php index ad6f2de981e..152c46e4b3e 100644 --- a/src/Rack.php +++ b/src/Rack.php @@ -182,7 +182,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/SoftwareLicense.php b/src/SoftwareLicense.php index 83082063a99..a03fce9e6e0 100644 --- a/src/SoftwareLicense.php +++ b/src/SoftwareLicense.php @@ -504,7 +504,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; $tab[] = [ diff --git a/src/State.php b/src/State.php index 41fdc22b480..8f41ef0850d 100644 --- a/src/State.php +++ b/src/State.php @@ -332,10 +332,10 @@ public function prepareInputForAdd($input) public function post_addItem() { - $state_visilibity = new DropdownVisibility(); + $state_visibility = new DropdownVisibility(); foreach ($this->getvisibilityFields() as $itemtype => $field) { if (isset($this->input[$field])) { - $state_visilibity->add([ + $state_visibility->add([ 'itemtype' => State::getType(), 'items_id' => $this->fields['id'], 'visible_itemtype' => $itemtype, @@ -349,16 +349,16 @@ public function post_addItem() public function post_updateItem($history = true) { - $state_visilibity = new DropdownVisibility(); + $state_visibility = new DropdownVisibility(); foreach ($this->getvisibilityFields() as $itemtype => $field) { if (isset($this->input[$field])) { - if ($state_visilibity->getFromDBByCrit(['itemtype' => self::getType(), 'items_id' => $this->input['id'], 'visible_itemtype' => $itemtype])) { - $state_visilibity->update([ - 'id' => $state_visilibity->fields['id'], + if ($state_visibility->getFromDBByCrit(['itemtype' => self::getType(), 'items_id' => $this->input['id'], 'visible_itemtype' => $itemtype])) { + $state_visibility->update([ + 'id' => $state_visibility->fields['id'], 'is_visible' => $this->input[$field] ]); } else { - $state_visilibity->add([ + $state_visibility->add([ 'itemtype' => State::getType(), 'items_id' => $this->fields['id'], 'visible_itemtype' => $itemtype, diff --git a/src/Unmanaged.php b/src/Unmanaged.php index 7e8d262b00f..fbad6679265 100644 --- a/src/Unmanaged.php +++ b/src/Unmanaged.php @@ -191,7 +191,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - 'condition' => self::getStateVisibilityCriteria() + 'condition' => $this->getStateVisibilityCriteria() ]; return $tab; diff --git a/templates/components/form/item_device.html.twig b/templates/components/form/item_device.html.twig index d72d39a757e..4c406f682f3 100644 --- a/templates/components/form/item_device.html.twig +++ b/templates/components/form/item_device.html.twig @@ -190,7 +190,7 @@ __('Status'), field_options|merge({ 'entity': item.fields['entities_id'], - 'condition': item.getStateVisibilityCriteria() ?? {} + 'condition': item is usingtrait('Glpi\\Features\\State') ? item.getStateVisibilityCriteria() : [] }) ) }} {% endif %} diff --git a/templates/generic_show_form.html.twig b/templates/generic_show_form.html.twig index eea7468502f..dcd997b651b 100644 --- a/templates/generic_show_form.html.twig +++ b/templates/generic_show_form.html.twig @@ -105,7 +105,7 @@ __('Status'), field_options|merge({ 'entity': item.fields['entities_id'], - 'condition': item.getStateVisibilityCriteria() ?? {} + 'condition': item is usingtrait('Glpi\\Features\\State') ? item.getStateVisibilityCriteria() : [] }) ) }} {% endif %} From eeae7f962eb8631b56a033df2d5a1bb09839760f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Tue, 27 Feb 2024 12:48:22 +0100 Subject: [PATCH 31/38] ensure all visibility fields are defined --- src/State.php | 6 ++++++ tests/functional/State.php | 18 +++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/State.php b/src/State.php index 8f41ef0850d..306d2a85866 100644 --- a/src/State.php +++ b/src/State.php @@ -850,6 +850,12 @@ public function getCloneRelations(): array public function post_getFromDB() { $statevisibility = new DropdownVisibility(); + + foreach ($this->getvisibilityFields() as $visibility_field) { + // Default value for fields that may not be yet stored in DB. + $this->fields[$visibility_field] = 0; + } + $visibilities = $statevisibility->find(['itemtype' => State::getType(), 'items_id' => $this->fields['id']]); foreach ($visibilities as $visibility) { $this->fields['is_visible_' . strtolower($visibility['visible_itemtype'])] = $visibility['is_visible']; diff --git a/tests/functional/State.php b/tests/functional/State.php index eadedbc5f10..9337d4fd3b6 100644 --- a/tests/functional/State.php +++ b/tests/functional/State.php @@ -86,6 +86,9 @@ public function testIsUnique(array $input, bool $expected) public function testVisibility() { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + $state = new \State(); $states_id = $state->add([ @@ -118,9 +121,18 @@ public function testVisibility() $this->boolean($state->getFromDB($states_id))->isTrue(); $this->string($state->fields['name'])->isEqualTo('Test computer and phone'); - $this->integer($state->fields['is_visible_computer'])->isIdenticalTo(0); - $this->integer($state->fields['is_visible_phone'])->isIdenticalTo(1); - $this->integer($state->fields['is_visible_printer'])->isIdenticalTo(1); + + $expected_values = []; + // Default values + foreach ($CFG_GLPI['state_types'] as $type) { + $expected_values['is_visible_' . strtolower($type)] = 0; + } + $expected_values['is_visible_computer'] = 0; + $expected_values['is_visible_phone'] = 1; + $expected_values['is_visible_printer'] = 1; + foreach ($expected_values as $field => $expected_value) { + $this->integer($state->fields[$field])->isIdenticalTo($expected_value); + } } public function testHasFeature() From 2f7a69dd372ba93dade6e78fe47658aee09766b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Tue, 27 Feb 2024 12:51:36 +0100 Subject: [PATCH 32/38] More resilient test --- tests/functional/State.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional/State.php b/tests/functional/State.php index 9337d4fd3b6..ab2e301eb17 100644 --- a/tests/functional/State.php +++ b/tests/functional/State.php @@ -150,15 +150,15 @@ public function testIsStateVisible() /** @var array $CFG_GLPI */ global $CFG_GLPI; + $itemtype = $CFG_GLPI['state_types'][0]; + $state = new \State(); $states_id = $state->add([ 'name' => 'Test computer and phone', - 'is_visible_computer' => '1' + 'is_visible_' . strtolower($itemtype) => '1' ]); $this->integer($states_id)->isGreaterThan(0); - $itemtype = $CFG_GLPI['state_types'][0]; - $item = new $itemtype(); $this->boolean(method_exists($itemtype, 'isStateVisible'))->isTrue($itemtype . ' misses isStateVisible() method!'); $this->boolean($item->isStateVisible($states_id))->isTrue(); @@ -173,7 +173,7 @@ function () use ($item, $states_id) { ) ->error() ->withType(E_USER_ERROR) - ->withMessage('Class Computer must be present in $CFG_GLPI[\'state_types\']') + ->withMessage(sprintf('Class %s must be present in $CFG_GLPI[\'state_types\']', $itemtype)) ->exists(); } From fdbe74f9ccec08cf9cb2b7abd49b3a879842e79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Tue, 27 Feb 2024 13:01:23 +0100 Subject: [PATCH 33/38] lint --- tests/functional/State.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/State.php b/tests/functional/State.php index ab2e301eb17..731caf42dd0 100644 --- a/tests/functional/State.php +++ b/tests/functional/State.php @@ -130,7 +130,7 @@ public function testVisibility() $expected_values['is_visible_computer'] = 0; $expected_values['is_visible_phone'] = 1; $expected_values['is_visible_printer'] = 1; - foreach ($expected_values as $field => $expected_value) { + foreach ($expected_values as $field => $expected_value) { $this->integer($state->fields[$field])->isIdenticalTo($expected_value); } } From 19c4a051b7122f6d6bce19b2697679d96cc8375f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Thu, 29 Feb 2024 14:37:31 +0100 Subject: [PATCH 34/38] All items with `states_id` field must be registered in `$CFG_GLPI['state_types']` --- inc/define.php | 1 + .../update_10.0.x_to_11.0.0/states.php | 3 + install/mysql/glpi-empty.sql | 2 + src/Item_Devices.php | 2 + .../components/form/item_device.html.twig | 4 +- templates/generic_show_form.html.twig | 4 +- tests/functional/State.php | 89 ++++++++++++++----- 7 files changed, 80 insertions(+), 25 deletions(-) diff --git a/inc/define.php b/inc/define.php index c963820c8c0..8282a1ca421 100644 --- a/inc/define.php +++ b/inc/define.php @@ -338,6 +338,7 @@ $CFG_GLPI['itemdevices'] = []; foreach ($CFG_GLPI['device_types'] as $dtype) { $CFG_GLPI['location_types'][] = 'Item_' . $dtype; + $CFG_GLPI['state_types'][] = 'Item_' . $dtype; $CFG_GLPI["itemdevices"][] = 'Item_' . $dtype; } diff --git a/install/migrations/update_10.0.x_to_11.0.0/states.php b/install/migrations/update_10.0.x_to_11.0.0/states.php index 4eb869b5146..05e2d3c4aa4 100644 --- a/install/migrations/update_10.0.x_to_11.0.0/states.php +++ b/install/migrations/update_10.0.x_to_11.0.0/states.php @@ -100,3 +100,6 @@ } } } + +$migration->addField('glpi_items_devicecameras', 'states_id', 'fkey'); +$migration->addKey('glpi_items_devicecameras', 'states_id'); diff --git a/install/mysql/glpi-empty.sql b/install/mysql/glpi-empty.sql index b0339e3e5e6..126b42fe71c 100644 --- a/install/mysql/glpi-empty.sql +++ b/install/mysql/glpi-empty.sql @@ -2011,6 +2011,7 @@ CREATE TABLE `glpi_items_devicecameras` ( `entities_id` int unsigned NOT NULL DEFAULT '0', `is_recursive` tinyint NOT NULL DEFAULT '0', `locations_id` int unsigned NOT NULL DEFAULT '0', + `states_id` int unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `items_id` (`items_id`), KEY `devicecameras_id` (`devicecameras_id`), @@ -2019,6 +2020,7 @@ CREATE TABLE `glpi_items_devicecameras` ( KEY `entities_id` (`entities_id`), KEY `is_recursive` (`is_recursive`), KEY `locations_id` (`locations_id`), + KEY `states_id` (`states_id`), KEY `item` (`itemtype`,`items_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; diff --git a/src/Item_Devices.php b/src/Item_Devices.php index f4949bb3f06..b8df30c4e73 100644 --- a/src/Item_Devices.php +++ b/src/Item_Devices.php @@ -46,6 +46,8 @@ **/ class Item_Devices extends CommonDBRelation { + use Glpi\Features\State; + public static $itemtype_1 = 'itemtype'; public static $items_id_1 = 'items_id'; public static $mustBeAttached_1 = false; diff --git a/templates/components/form/item_device.html.twig b/templates/components/form/item_device.html.twig index 4c406f682f3..cbe6a42b938 100644 --- a/templates/components/form/item_device.html.twig +++ b/templates/components/form/item_device.html.twig @@ -182,7 +182,7 @@ ) }} {% endif %} - {% if item.isField('states_id') %} + {% if item.isField('states_id') and item is usingtrait('Glpi\\Features\\State') %} {{ fields.dropdownField( 'State', 'states_id', @@ -190,7 +190,7 @@ __('Status'), field_options|merge({ 'entity': item.fields['entities_id'], - 'condition': item is usingtrait('Glpi\\Features\\State') ? item.getStateVisibilityCriteria() : [] + 'condition': item.getStateVisibilityCriteria() }) ) }} {% endif %} diff --git a/templates/generic_show_form.html.twig b/templates/generic_show_form.html.twig index dcd997b651b..01eab96ed69 100644 --- a/templates/generic_show_form.html.twig +++ b/templates/generic_show_form.html.twig @@ -97,7 +97,7 @@ {% endif %} {% endif %} - {% if item.isField('states_id') %} + {% if item.isField('states_id') and item is usingtrait('Glpi\\Features\\State') %} {{ fields.dropdownField( 'State', 'states_id', @@ -105,7 +105,7 @@ __('Status'), field_options|merge({ 'entity': item.fields['entities_id'], - 'condition': item is usingtrait('Glpi\\Features\\State') ? item.getStateVisibilityCriteria() : [] + 'condition': item.getStateVisibilityCriteria() }) ) }} {% endif %} diff --git a/tests/functional/State.php b/tests/functional/State.php index 731caf42dd0..3528b4d3115 100644 --- a/tests/functional/State.php +++ b/tests/functional/State.php @@ -35,12 +35,18 @@ namespace tests\units; +use CommonDBTM; +use Computer; use DbTestCase; -use Generator; +use DropdownVisibility; +use Phone; +use Printer; +use ReflectionClass; +use Toolbox; class State extends DbTestCase { - protected function testIsUniqueProvider(): Generator + protected function testIsUniqueProvider(): iterable { // Insert test data $this->createItems("State", [ @@ -78,13 +84,13 @@ protected function testIsUniqueProvider(): Generator /** * @dataprovider testIsUniqueProvider */ - public function testIsUnique(array $input, bool $expected) + public function testIsUnique(array $input, bool $expected): void { $state = new \State(); $this->boolean($state->isUnique($input))->isEqualTo($expected); } - public function testVisibility() + public function testVisibility(): void { /** @var array $CFG_GLPI */ global $CFG_GLPI; @@ -99,12 +105,12 @@ public function testVisibility() $this->integer($states_id)->isGreaterThan(0); - $statevisibility = new \DropdownVisibility(); + $statevisibility = new DropdownVisibility(); $visibilities = $statevisibility->find(['itemtype' => \State::getType(), 'items_id' => $states_id]); $this->array($visibilities)->hasSize(2); - $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Computer::getType(), 'is_visible' => 1]))->isTrue(); - $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Phone::getType(), 'is_visible' => 1]))->isTrue(); - $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Printer::getType(), 'is_visible' => 0]))->isFalse(); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => Computer::getType(), 'is_visible' => 1]))->isTrue(); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => Phone::getType(), 'is_visible' => 1]))->isTrue(); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => Printer::getType(), 'is_visible' => 0]))->isFalse(); $state->update([ 'id' => $states_id, @@ -115,9 +121,9 @@ public function testVisibility() $this->array($visibilities)->hasSize(3); $visibilities = $statevisibility->find(['itemtype' => \State::getType(), 'items_id' => $states_id, 'is_visible' => 1]); $this->array($visibilities)->hasSize(2); - $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Computer::getType(), 'is_visible' => 0]))->isTrue(); - $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Phone::getType(), 'is_visible' => 1]))->isTrue(); - $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => \Printer::getType(), 'is_visible' => 1]))->isTrue(); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => Computer::getType(), 'is_visible' => 0]))->isTrue(); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => Phone::getType(), 'is_visible' => 1]))->isTrue(); + $this->boolean($statevisibility->getFromDBByCrit(['itemtype' => \State::getType(), 'items_id' => $states_id, 'visible_itemtype' => Printer::getType(), 'is_visible' => 1]))->isTrue(); $this->boolean($state->getFromDB($states_id))->isTrue(); $this->string($state->fields['name'])->isEqualTo('Test computer and phone'); @@ -135,17 +141,58 @@ public function testVisibility() } } - public function testHasFeature() + public function testHasFeature(): void { /** @var array $CFG_GLPI */ global $CFG_GLPI; foreach ($CFG_GLPI['state_types'] as $itemtype) { - $this->boolean(method_exists($itemtype, 'isStateVisible'))->isTrue($itemtype . ' misses isStateVisible() method!'); + $this->boolean(Toolbox::hasTrait($itemtype, \Glpi\Features\State::class))->isTrue( + $itemtype . ' misses ' . \Glpi\Features\State::class . ' trait!' + ); } } - public function testIsStateVisible() + public function testRegisteredTypes(): void + { + /** + * @var array $CFG_GLPI + * @var \DBmysql $DB + */ + global $CFG_GLPI, $DB; + + foreach ($CFG_GLPI['state_types'] as $itemtype) { + $this->boolean($DB->fieldExists($itemtype::getTable(), 'states_id'))->isTrue( + $itemtype . ' should have a `states_id` field.' + ); + } + + foreach ($DB->listTables() as $table_data) { + $table_name = $table_data['TABLE_NAME']; + $classname = getItemTypeForTable($table_name); + + if ( + $classname === \State::class + || !is_a($classname, CommonDBTM::class, true) + || (new ReflectionClass($classname))->isAbstract() + ) { + continue; + } + + if (in_array($classname, ['DeviceGeneric', 'DeviceSensor'])) { + // FIXME This field should probably not exist for these itemtypes. + continue; + } + + $has_field = $DB->fieldExists($table_name, 'states_id'); + $this->array($CFG_GLPI['state_types'])->{$has_field ? 'contains' : 'notContains'}( + $classname, + $classname . ' should be declared in `$CFG_GLPI[\'state_types\']`.' + ); + } + } + + public function testIsStateVisible(): void { /** @var array $CFG_GLPI */ global $CFG_GLPI; @@ -177,7 +224,7 @@ function () use ($item, $states_id) { ->exists(); } - public function testGetStateVisibilityCriteria() + public function testGetStateVisibilityCriteria(): void { /** @var array $CFG_GLPI */ global $CFG_GLPI; @@ -187,21 +234,21 @@ public function testGetStateVisibilityCriteria() $item = new $itemtype(); $this->array($item->getStateVisibilityCriteria())->isIdenticalTo([ 'LEFT JOIN' => [ - \DropdownVisibility::getTable() => [ + DropdownVisibility::getTable() => [ 'ON' => [ - \DropdownVisibility::getTable() => 'items_id', + DropdownVisibility::getTable() => 'items_id', \State::getTable() => 'id', [ 'AND' => [ - \DropdownVisibility::getTable() . '.itemtype' => \State::getType() + DropdownVisibility::getTable() . '.itemtype' => \State::getType() ] ] ] ] ], 'WHERE' => [ - \DropdownVisibility::getTable() . '.itemtype' => \State::getType(), - \DropdownVisibility::getTable() . '.visible_itemtype' => $itemtype, - \DropdownVisibility::getTable() . '.is_visible' => 1 + DropdownVisibility::getTable() . '.itemtype' => \State::getType(), + DropdownVisibility::getTable() . '.visible_itemtype' => $itemtype, + DropdownVisibility::getTable() . '.is_visible' => 1 ] ]); } From 8338b004cf66df055b8e9188712b3d90cff5c44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Thu, 29 Feb 2024 14:51:59 +0100 Subject: [PATCH 35/38] Fix field name --- src/DropdownVisibility.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/DropdownVisibility.php b/src/DropdownVisibility.php index 2d23e20cf8d..7fccf0ea0fa 100644 --- a/src/DropdownVisibility.php +++ b/src/DropdownVisibility.php @@ -35,9 +35,8 @@ class DropdownVisibility extends CommonDBChild { - public static $mustBeAttached = false; //no idea why. public static $itemtype = 'itemtype'; - public static $items_id = 'states_id'; + public static $items_id = 'items_id'; public $dohistory = false; public static $logs_for_parent = false; } From 94b7569074795ebe60bf4f4cad8f22700d53b69f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Thu, 29 Feb 2024 14:58:34 +0100 Subject: [PATCH 36/38] Apply new logic to generic assets --- src/Asset/Asset.php | 6 +++--- src/Asset/AssetDefinitionManager.php | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Asset/Asset.php b/src/Asset/Asset.php index f6a1e0e7357..737a76f6684 100644 --- a/src/Asset/Asset.php +++ b/src/Asset/Asset.php @@ -38,7 +38,6 @@ use CommonDBTM; use Glpi\Application\View\TemplateRenderer; use Entity; -use Glpi\Features\Clonable; use Group; use Location; use Manufacturer; @@ -48,7 +47,8 @@ abstract class Asset extends CommonDBTM { - use Clonable; + use \Glpi\Features\Clonable; + use \Glpi\Features\State; final public function __construct() { @@ -189,7 +189,7 @@ public function rawSearchOptions() 'field' => 'completename', 'name' => __('Status'), 'datatype' => 'dropdown', - // TODO 'condition' to filter values + 'condition' => $this->getStateVisibilityCriteria(), ]; $search_options[] = [ diff --git a/src/Asset/AssetDefinitionManager.php b/src/Asset/AssetDefinitionManager.php index baf630abc81..1036e516fc0 100644 --- a/src/Asset/AssetDefinitionManager.php +++ b/src/Asset/AssetDefinitionManager.php @@ -178,6 +178,7 @@ private function boostrapConcreteClass(AssetDefinition $definition): void 'linkuser_tech_types', 'linkgroup_tech_types', 'location_types', + 'state_types', 'ticket_types', ]; foreach ($config_keys as $config_key) { From ad00a689fe54c7d3af082ce7d6d61c425242ccb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Mon, 4 Mar 2024 09:29:08 +0100 Subject: [PATCH 37/38] fixes --- inc/relation.constant.php | 1 + install/migrations/update_10.0.x_to_11.0.0/states.php | 8 ++++++++ install/mysql/glpi-empty.sql | 4 ---- tests/functional/Glpi/Inventory/Inventory.php | 2 ++ tests/functional/State.php | 5 ----- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/inc/relation.constant.php b/inc/relation.constant.php index 62c0a6fefcb..431aa6a77ad 100644 --- a/inc/relation.constant.php +++ b/inc/relation.constant.php @@ -1404,6 +1404,7 @@ 'glpi_devicesensors' => 'states_id', 'glpi_enclosures' => 'states_id', 'glpi_items_devicebatteries' => 'states_id', + 'glpi_items_devicecameras' => 'states_id', 'glpi_items_devicecases' => 'states_id', 'glpi_items_devicecontrols' => 'states_id', 'glpi_items_devicedrives' => 'states_id', diff --git a/install/migrations/update_10.0.x_to_11.0.0/states.php b/install/migrations/update_10.0.x_to_11.0.0/states.php index 05e2d3c4aa4..ebf15a8c173 100644 --- a/install/migrations/update_10.0.x_to_11.0.0/states.php +++ b/install/migrations/update_10.0.x_to_11.0.0/states.php @@ -100,6 +100,14 @@ } } } +$migration->displayWarning( + 'States dropdown in devices items forms are now filtered, and, by default, existing states are not visible.' +); +// Add missing field $migration->addField('glpi_items_devicecameras', 'states_id', 'fkey'); $migration->addKey('glpi_items_devicecameras', 'states_id'); + +// Drop unexpected fields +$migration->dropField('glpi_devicegenerics', 'states_id'); +$migration->dropField('glpi_devicesensors', 'states_id'); diff --git a/install/mysql/glpi-empty.sql b/install/mysql/glpi-empty.sql index 126b42fe71c..ab86569c8db 100644 --- a/install/mysql/glpi-empty.sql +++ b/install/mysql/glpi-empty.sql @@ -1842,7 +1842,6 @@ CREATE TABLE `glpi_devicegenerics` ( `entities_id` int unsigned NOT NULL DEFAULT '0', `is_recursive` tinyint NOT NULL DEFAULT '0', `locations_id` int unsigned NOT NULL DEFAULT '0', - `states_id` int unsigned NOT NULL DEFAULT '0', `devicegenericmodels_id` int unsigned DEFAULT NULL, `date_mod` timestamp NULL DEFAULT NULL, `date_creation` timestamp NULL DEFAULT NULL, @@ -1853,7 +1852,6 @@ CREATE TABLE `glpi_devicegenerics` ( KEY `entities_id` (`entities_id`), KEY `is_recursive` (`is_recursive`), KEY `locations_id` (`locations_id`), - KEY `states_id` (`states_id`), KEY `date_mod` (`date_mod`), KEY `date_creation` (`date_creation`), KEY `devicegenericmodels_id` (`devicegenericmodels_id`) @@ -2378,7 +2376,6 @@ CREATE TABLE `glpi_devicesensors` ( `entities_id` int unsigned NOT NULL DEFAULT '0', `is_recursive` tinyint NOT NULL DEFAULT '0', `locations_id` int unsigned NOT NULL DEFAULT '0', - `states_id` int unsigned NOT NULL DEFAULT '0', `date_mod` timestamp NULL DEFAULT NULL, `date_creation` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`), @@ -2388,7 +2385,6 @@ CREATE TABLE `glpi_devicesensors` ( KEY `entities_id` (`entities_id`), KEY `is_recursive` (`is_recursive`), KEY `locations_id` (`locations_id`), - KEY `states_id` (`states_id`), KEY `date_mod` (`date_mod`), KEY `date_creation` (`date_creation`), KEY `devicesensormodels_id` (`devicesensormodels_id`) diff --git a/tests/functional/Glpi/Inventory/Inventory.php b/tests/functional/Glpi/Inventory/Inventory.php index 77cec63b07f..3a244d04c46 100644 --- a/tests/functional/Glpi/Inventory/Inventory.php +++ b/tests/functional/Glpi/Inventory/Inventory.php @@ -5528,6 +5528,7 @@ public function testImportPhone() 'entities_id' => 0, 'is_recursive' => 0, 'locations_id' => 0, + 'states_id' => 0, ], [ 'items_id' => $phones_id, 'itemtype' => 'Phone', @@ -5537,6 +5538,7 @@ public function testImportPhone() 'entities_id' => 0, 'is_recursive' => 0, 'locations_id' => 0, + 'states_id' => 0, ] ] ]; diff --git a/tests/functional/State.php b/tests/functional/State.php index 3528b4d3115..24002669b9d 100644 --- a/tests/functional/State.php +++ b/tests/functional/State.php @@ -179,11 +179,6 @@ public function testRegisteredTypes(): void continue; } - if (in_array($classname, ['DeviceGeneric', 'DeviceSensor'])) { - // FIXME This field should probably not exist for these itemtypes. - continue; - } - $has_field = $DB->fieldExists($table_name, 'states_id'); $this->array($CFG_GLPI['state_types'])->{$has_field ? 'contains' : 'notContains'}( $classname, From 2df827132a96affc605bf2add2a46a57c3be8efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Mon, 4 Mar 2024 10:10:30 +0100 Subject: [PATCH 38/38] fix tests --- inc/relation.constant.php | 2 -- src/Api/HL/Controller/ComponentController.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/inc/relation.constant.php b/inc/relation.constant.php index 431aa6a77ad..46b25e2c754 100644 --- a/inc/relation.constant.php +++ b/inc/relation.constant.php @@ -1400,8 +1400,6 @@ 'glpi_computers' => 'states_id', 'glpi_contracts' => 'states_id', 'glpi_databaseinstances' => 'states_id', - 'glpi_devicegenerics' => 'states_id', - 'glpi_devicesensors' => 'states_id', 'glpi_enclosures' => 'states_id', 'glpi_items_devicebatteries' => 'states_id', 'glpi_items_devicecameras' => 'states_id', diff --git a/src/Api/HL/Controller/ComponentController.php b/src/Api/HL/Controller/ComponentController.php index 8f96cef2c59..804580535de 100644 --- a/src/Api/HL/Controller/ComponentController.php +++ b/src/Api/HL/Controller/ComponentController.php @@ -241,7 +241,6 @@ protected static function getRawKnownSchemas(): array 'type' => self::getDropdownTypeSchema(class: \DeviceGenericType::class, full_schema: 'GenericDeviceType'), 'model' => self::getDropdownTypeSchema(class: \DeviceGenericModel::class, full_schema: 'GenericDeviceModel'), 'location' => self::getDropdownTypeSchema(class: \Location::class, full_schema: 'Location'), - 'state' => self::getDropdownTypeSchema(class: \State::class, full_schema: 'State'), ] ], 'GraphicCardModel' => [ @@ -373,7 +372,6 @@ protected static function getRawKnownSchemas(): array 'type' => self::getDropdownTypeSchema(class: \DeviceSensorType::class, full_schema: 'SensorType'), 'model' => self::getDropdownTypeSchema(class: \DeviceSensorModel::class, full_schema: 'SensorModel'), 'location' => self::getDropdownTypeSchema(class: \Location::class, full_schema: 'Location'), - 'state' => self::getDropdownTypeSchema(class: \State::class, full_schema: 'State'), ] ], 'SIMCardType' => [