From cf6842de8b4c5748b1a4cfc14a1cacb141bdc747 Mon Sep 17 00:00:00 2001 From: Curtis Conard Date: Sun, 11 Aug 2024 17:40:39 -0400 Subject: [PATCH 1/7] add type and model dicts --- front/asset/ruledictionarymodel.form.php | 51 ++++++ front/asset/ruledictionarymodel.php | 51 ++++++ front/asset/ruledictionarytype.form.php | 51 ++++++ front/asset/ruledictionarytype.php | 51 ++++++ phpunit/DbTestCase.php | 10 +- .../functional/Glpi/Asset/DictionaryTest.php | 119 +++++++++++++ phpunit/functional/HtmlTest.php | 2 +- src/Glpi/Api/HL/Controller/RuleController.php | 2 +- src/Glpi/Asset/AssetDefinition.php | 35 +++- src/Glpi/Asset/AssetDefinitionManager.php | 159 ++++++++++++++++++ src/Rule.php | 31 ++++ src/RuleCollection.php | 64 ++++--- src/RuleCommonITILObjectCollection.php | 4 +- src/RuleDictionnaryDropdownCollection.php | 2 +- 14 files changed, 597 insertions(+), 35 deletions(-) create mode 100644 front/asset/ruledictionarymodel.form.php create mode 100644 front/asset/ruledictionarymodel.php create mode 100644 front/asset/ruledictionarytype.form.php create mode 100644 front/asset/ruledictionarytype.php create mode 100644 phpunit/functional/Glpi/Asset/DictionaryTest.php diff --git a/front/asset/ruledictionarymodel.form.php b/front/asset/ruledictionarymodel.form.php new file mode 100644 index 00000000000..8ec1ac8542f --- /dev/null +++ b/front/asset/ruledictionarymodel.form.php @@ -0,0 +1,51 @@ +. + * + * --------------------------------------------------------------------- + */ + +use Glpi\Asset\AssetDefinition; +use Glpi\Http\Response; + +$definition = new AssetDefinition(); +$classname = array_key_exists('class', $_GET) && $definition->getFromDBBySystemName((string)$_GET['class']) + ? $definition->getAssetClassName() + : null; + +if ($classname === null || !class_exists($classname)) { + Response::sendError(400, 'Bad request', Response::CONTENT_TYPE_TEXT_HTML); +} + +$rulecollection_class = $definition->getAssetModelDictionaryCollectionClassName(); +$rulecollection = new $rulecollection_class(); + +include(GLPI_ROOT . "/front/rule.common.form.php"); diff --git a/front/asset/ruledictionarymodel.php b/front/asset/ruledictionarymodel.php new file mode 100644 index 00000000000..745e82b76c0 --- /dev/null +++ b/front/asset/ruledictionarymodel.php @@ -0,0 +1,51 @@ +. + * + * --------------------------------------------------------------------- + */ + +use Glpi\Asset\AssetDefinition; +use Glpi\Http\Response; + +$definition = new AssetDefinition(); +$classname = array_key_exists('class', $_GET) && $definition->getFromDBBySystemName((string)$_GET['class']) + ? $definition->getAssetClassName() + : null; + +if ($classname === null || !class_exists($classname)) { + Response::sendError(400, 'Bad request', Response::CONTENT_TYPE_TEXT_HTML); +} + +$rulecollection_class = $definition->getAssetModelDictionaryCollectionClassName(); +$rulecollection = new $rulecollection_class(); + +include(GLPI_ROOT . "/front/rule.common.php"); diff --git a/front/asset/ruledictionarytype.form.php b/front/asset/ruledictionarytype.form.php new file mode 100644 index 00000000000..2cc607ed9d8 --- /dev/null +++ b/front/asset/ruledictionarytype.form.php @@ -0,0 +1,51 @@ +. + * + * --------------------------------------------------------------------- + */ + +use Glpi\Asset\AssetDefinition; +use Glpi\Http\Response; + +$definition = new AssetDefinition(); +$classname = array_key_exists('class', $_GET) && $definition->getFromDBBySystemName((string)$_GET['class']) + ? $definition->getAssetClassName() + : null; + +if ($classname === null || !class_exists($classname)) { + Response::sendError(400, 'Bad request', Response::CONTENT_TYPE_TEXT_HTML); +} + +$rulecollection_class = $definition->getAssetTypeDictionaryCollectionClassName(); +$rulecollection = new $rulecollection_class(); + +include(GLPI_ROOT . "/front/rule.common.form.php"); diff --git a/front/asset/ruledictionarytype.php b/front/asset/ruledictionarytype.php new file mode 100644 index 00000000000..928de3eb9c9 --- /dev/null +++ b/front/asset/ruledictionarytype.php @@ -0,0 +1,51 @@ +. + * + * --------------------------------------------------------------------- + */ + +use Glpi\Asset\AssetDefinition; +use Glpi\Http\Response; + +$definition = new AssetDefinition(); +$classname = array_key_exists('class', $_GET) && $definition->getFromDBBySystemName((string)$_GET['class']) + ? $definition->getAssetClassName() + : null; + +if ($classname === null || !class_exists($classname)) { + Response::sendError(400, 'Bad request', Response::CONTENT_TYPE_TEXT_HTML); +} + +$rulecollection_class = $definition->getAssetTypeDictionaryCollectionClassName(); +$rulecollection = new $rulecollection_class(); + +include(GLPI_ROOT . "/front/rule.common.php"); diff --git a/phpunit/DbTestCase.php b/phpunit/DbTestCase.php index 78406754e6a..136387e34b1 100644 --- a/phpunit/DbTestCase.php +++ b/phpunit/DbTestCase.php @@ -348,14 +348,8 @@ protected function initAssetDefinition( ], skip_fields: ['capacities', 'profiles'] // JSON encoded fields cannot be automatically checked ); - $this->assertEquals( - $capacities, - $this->callPrivateMethod($definition, 'getDecodedCapacitiesField') - ); - $this->assertEquals( - $profiles, - $this->callPrivateMethod($definition, 'getDecodedProfilesField') - ); + $this->assertEquals($capacities, $this->callPrivateMethod($definition, 'getDecodedCapacitiesField')); + $this->assertEquals($profiles, $this->callPrivateMethod($definition, 'getDecodedProfilesField')); $manager = AssetDefinitionManager::getInstance(); $this->callPrivateMethod($manager, 'loadConcreteClass', $definition); diff --git a/phpunit/functional/Glpi/Asset/DictionaryTest.php b/phpunit/functional/Glpi/Asset/DictionaryTest.php new file mode 100644 index 00000000000..504c96c6541 --- /dev/null +++ b/phpunit/functional/Glpi/Asset/DictionaryTest.php @@ -0,0 +1,119 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace tests\units\Glpi\Asset; + +use DbTestCase; +use Rule; +use RuleCollection; +use Session; + +class DictionaryTest extends DbTestCase +{ + public function testInDictionaryList() + { + $this->login(); + + $definition = $this->initAssetDefinition(); + $dictionaries = RuleCollection::getDictionnaries(); + + $has_model_dictionary = false; + $has_type_dictionary = false; + + foreach ($dictionaries as $group) { + if ($group['type'] === 'Models') { + foreach ($group['entries'] as $entry) { + if ( + $entry['label'] === $definition->getAssetModelClassName()::getTypeName(Session::getPluralNumber()) + && str_contains($entry['link'], 'front/asset/ruledictionarymodel.php?class=' . $definition->fields['system_name']) + && $entry['icon'] === $definition->getAssetModelClassName()::getIcon() + ) { + $has_model_dictionary = true; + break; + } + } + } else if ($group['type'] === 'Types') { + foreach ($group['entries'] as $entry) { + if ( + $entry['label'] === $definition->getAssetTypeClassName()::getTypeName(Session::getPluralNumber()) + && str_contains($entry['link'], 'front/asset/ruledictionarytype.php?class=' . $definition->fields['system_name']) + && $entry['icon'] === $definition->getAssetTypeClassName()::getIcon() + ) { + $has_type_dictionary = true; + break; + } + } + } + } + + $this->assertTrue($has_model_dictionary); + $this->assertTrue($has_type_dictionary); + } + + public function testMenuContent() + { + $this->login(); + $definition = $this->initAssetDefinition(); + $rule_menu_content = Rule::getMenuContent(); + $model_key = 'model.' . $definition->fields['system_name']; + $type_key = 'type.' . $definition->fields['system_name']; + + $this->assertArrayHasKey($model_key, $rule_menu_content['dictionnary']['options']); + $this->assertArrayHasKey($type_key, $rule_menu_content['dictionnary']['options']); + + $this->assertEquals( + $definition->getAssetModelClassName()::getTypeName(Session::getPluralNumber()), + $rule_menu_content['dictionnary']['options'][$model_key]['title'] + ); + $model_page = $rule_menu_content['dictionnary']['options'][$model_key]['page']; + $this->assertEquals('/front/asset/ruledictionarymodel.php?class=' . $definition->fields['system_name'], $model_page); + $this->assertEquals($model_page, $rule_menu_content['dictionnary']['options'][$model_key]['links']['search']); + $this->assertStringContainsString( + '/front/asset/ruledictionarymodel.form.php?class=' . $definition->fields['system_name'], + $rule_menu_content['dictionnary']['options'][$model_key]['links']['add'] + ); + + $this->assertEquals( + $definition->getAssetTypeClassName()::getTypeName(Session::getPluralNumber()), + $rule_menu_content['dictionnary']['options'][$type_key]['title'] + ); + $type_page = $rule_menu_content['dictionnary']['options'][$type_key]['page']; + $this->assertEquals('/front/asset/ruledictionarytype.php?class=' . $definition->fields['system_name'], $type_page); + $this->assertEquals($type_page, $rule_menu_content['dictionnary']['options'][$type_key]['links']['search']); + $this->assertStringContainsString( + '/front/asset/ruledictionarytype.form.php?class=' . $definition->fields['system_name'], + $rule_menu_content['dictionnary']['options'][$type_key]['links']['add'] + ); + } +} diff --git a/phpunit/functional/HtmlTest.php b/phpunit/functional/HtmlTest.php index 5fc6bbd3897..3a832816fb6 100644 --- a/phpunit/functional/HtmlTest.php +++ b/phpunit/functional/HtmlTest.php @@ -270,7 +270,7 @@ public function testGetMenuInfos() 'Item_DeviceSimcard' ]; $this->assertSame('Assets', $menu['assets']['title']); - $this->assertSame($expected, $menu['assets']['types']); + $this->assertSame($expected, array_intersect($expected, $menu['assets']['types'])); $expected = [ 'Ticket', diff --git a/src/Glpi/Api/HL/Controller/RuleController.php b/src/Glpi/Api/HL/Controller/RuleController.php index 6ac346e1d5d..0a19876feb8 100644 --- a/src/Glpi/Api/HL/Controller/RuleController.php +++ b/src/Glpi/Api/HL/Controller/RuleController.php @@ -311,7 +311,7 @@ public function getCollections(Request $request): Response /** @var \RuleCollection $instance */ $instance = new $collection(); if ($instance->canList()) { - $rule_class = $instance->getRuleClassName(); + $rule_class = $instance::getRuleClassName(); if (str_starts_with($rule_class, 'Rule')) { // Only handle rules from the core in the global namespace here $visible_collections[] = [ diff --git a/src/Glpi/Asset/AssetDefinition.php b/src/Glpi/Asset/AssetDefinition.php index 349471921a3..1edc5f25163 100644 --- a/src/Glpi/Asset/AssetDefinition.php +++ b/src/Glpi/Asset/AssetDefinition.php @@ -48,6 +48,7 @@ use Glpi\Search\SearchOption; use Profile; use ProfileRight; +use RuleDictionnaryDropdownCollection; use Session; final class AssetDefinition extends CommonDBTM @@ -876,7 +877,7 @@ public function getAssetClassName(bool $with_namespace = true): string * Get the definition's concrete asset model class name. * * @param bool $with_namespace - * @return string + * @return class-string */ public function getAssetModelClassName(bool $with_namespace = true): string { @@ -887,13 +888,43 @@ public function getAssetModelClassName(bool $with_namespace = true): string * Get the definition's concrete asset type class name. * * @param bool $with_namespace - * @return string + * @return class-string */ public function getAssetTypeClassName(bool $with_namespace = true): string { return $this->getAssetClassName($with_namespace) . 'Type'; } + /** + * Get the definition's concrete asset model dictionary collection class name. + * + * @param bool $with_namespace + * @return class-string + */ + public function getAssetModelDictionaryCollectionClassName(bool $with_namespace = true): string + { + $classname = 'RuleDictionary' . $this->getAssetModelClassName(false) . 'Collection'; + if ($with_namespace) { + $classname = 'Glpi\\CustomAsset\\' . $classname; + } + return $classname; + } + + /** + * Get the definition's concrete asset type dictionary collection class name. + * + * @param bool $with_namespace + * @return class-string + */ + public function getAssetTypeDictionaryCollectionClassName(bool $with_namespace = true): string + { + $classname = 'RuleDictionary' . $this->getAssetTypeClassName(false) . 'Collection'; + if ($with_namespace) { + $classname = 'Glpi\\CustomAsset\\' . $classname; + } + return $classname; + } + /** * Get the definition's concrete asset rightname. * diff --git a/src/Glpi/Asset/AssetDefinitionManager.php b/src/Glpi/Asset/AssetDefinitionManager.php index 90e12bab510..54c2b0c9d79 100644 --- a/src/Glpi/Asset/AssetDefinitionManager.php +++ b/src/Glpi/Asset/AssetDefinitionManager.php @@ -193,6 +193,10 @@ private function boostrapConcreteClass(AssetDefinition $definition): void $CFG_GLPI[$config_key][] = $asset_class_name; } + // Add type and model to dictionnary config entry + $CFG_GLPI['dictionnary_types'][] = $definition->getAssetTypeClassName(); + $CFG_GLPI['dictionnary_types'][] = $definition->getAssetModelClassName(); + // Bootstrap capacities foreach ($capacities as $capacity) { if ($definition->hasCapacityEnabled($capacity)) { @@ -229,6 +233,10 @@ private function boostrapConcreteClass(AssetDefinition $definition): void public function autoloadAssetClass(string $classname): void { $patterns = [ + '/^Glpi\\\CustomAsset\\\RuleDictionary([A-Za-z]+)ModelCollection$/' => 'loadConcreteModelDictionaryCollectionClass', + '/^Glpi\\\CustomAsset\\\RuleDictionary([A-Za-z]+)TypeCollection$/' => 'loadConcreteTypeDictionaryCollectionClass', + '/^Glpi\\\CustomAsset\\\RuleDictionary([A-Za-z]+)Model$/' => 'loadConcreteModelDictionaryClass', + '/^Glpi\\\CustomAsset\\\RuleDictionary([A-Za-z]+)Type$/' => 'loadConcreteTypeDictionaryClass', '/^Glpi\\\CustomAsset\\\([A-Za-z]+)Model$/' => 'loadConcreteModelClass', '/^Glpi\\\CustomAsset\\\([A-Za-z]+)Type$/' => 'loadConcreteTypeClass', '/^Glpi\\\CustomAsset\\\([A-Za-z]+)$/' => 'loadConcreteClass', @@ -447,4 +455,155 @@ final class {$definition->getAssetTypeClassName(false)} extends AssetType { $reflected_class = new ReflectionClass($definition->getAssetTypeClassName()); $reflected_class->setStaticPropertyValue('definition', $definition); } + + private function loadConcreteModelDictionaryClass(AssetDefinition $definition): void + { + $model_class = $definition->getAssetModelClassName(); + eval(<<getAssetModelClassName(false)} extends RuleDictionnaryDropdown +{ + public function getCriterias() + { + static \$criterias = []; + + if (count(\$criterias)) { + return \$criterias; + } + + \$criterias['name']['field'] = 'name'; + \$criterias['name']['name'] = _n('Model', 'Models', 1); + \$criterias['name']['table'] = '{$model_class::getTable()}'; + + \$criterias['manufacturer']['field'] = 'name'; + \$criterias['manufacturer']['name'] = Manufacturer::getTypeName(1); + \$criterias['manufacturer']['table'] = 'glpi_manufacturers'; + + return \$criterias; + } + + public function getActions() + { + \$actions = []; + \$actions['name']['name'] = _n('Model', 'Models', 1); + \$actions['name']['force_actions'] = ['append_regex_result', 'assign', 'regex_result']; + + return \$actions; + } + + public static function getSearchURL(\$full = true) + { + /** @var array \$CFG_GLPI */ + global \$CFG_GLPI; + return (\$full ? \$CFG_GLPI['root_doc'] : '') . '/front/asset/ruledictionarymodel.php?class={$definition->fields['system_name']}'; + } + + public static function getFormURL(\$full = true) + { + /** @var array \$CFG_GLPI */ + global \$CFG_GLPI; + return (\$full ? \$CFG_GLPI['root_doc'] : '') . '/front/asset/ruledictionarymodel.form.php?class={$definition->fields['system_name']}'; + } +} +PHP + ); + } + + private function loadConcreteTypeDictionaryClass(AssetDefinition $definition): void + { + eval(<<getAssetTypeClassName(false)} extends RuleDictionnaryDropdown +{ + public function getCriterias() + { + static \$criterias = []; + + if (count(\$criterias)) { + return \$criterias; + } + + \$criterias['name']['field'] = 'name'; + \$criterias['name']['name'] = _n('Type', 'Types', 1); + \$criterias['name']['table'] = '{$definition->getAssetTypeClassName()::getTable()}'; + + return \$criterias; + } + + public function getActions() + { + \$actions = []; + \$actions['name']['name'] = _n('Type', 'Types', 1); + \$actions['name']['force_actions'] = ['append_regex_result', 'assign','regex_result']; + + return \$actions; + } + + public static function getSearchURL(\$full = true) + { + /** @var array \$CFG_GLPI */ + global \$CFG_GLPI; + return (\$full ? \$CFG_GLPI['root_doc'] : '') . '/front/asset/ruledictionarytype.php?class={$definition->fields['system_name']}'; + } + + public static function getFormURL(\$full = true) + { + /** @var array \$CFG_GLPI */ + global \$CFG_GLPI; + return (\$full ? \$CFG_GLPI['root_doc'] : '') . '/front/asset/ruledictionarytype.form.php?class={$definition->fields['system_name']}'; + } +} +PHP + ); + } + + private function loadConcreteModelDictionaryCollectionClass(AssetDefinition $definition): void + { + $model_class = $definition->getAssetModelClassName(); + eval(<<getAssetModelClassName(false)}Collection extends RuleDictionnaryDropdownCollection +{ + public \$item_table = '{$model_class::getTable()}'; + public \$menu_option = "model.{$definition->fields['system_name']}"; + + public function getTitle() + { + return sprintf(__('Dictionary of %s'), '{$model_class::getTypeName()}'); + } +} +PHP + ); + } + + private function loadConcreteTypeDictionaryCollectionClass(AssetDefinition $definition): void + { + $type_class = $definition->getAssetTypeClassName(); + eval(<<getAssetTypeClassName(false)}Collection extends RuleDictionnaryDropdownCollection +{ + public \$item_table = '{$type_class::getTable()}'; + public \$menu_option = "model.{$definition->fields['system_name']}"; + + public function getTitle() + { + return sprintf(__('Dictionary of %s'), '{$type_class::getTypeName()}'); + } +} +PHP + ); + } } diff --git a/src/Rule.php b/src/Rule.php index c65c5edcbd5..a6a08da74cb 100644 --- a/src/Rule.php +++ b/src/Rule.php @@ -508,6 +508,37 @@ public static function getMenuContent() } } + $asset_definitions = \Glpi\Asset\AssetDefinitionManager::getInstance()->getDefinitions(true); + foreach ($asset_definitions as $definition) { + $model_dictionary_collection = $definition->getAssetModelDictionaryCollectionClassName(); + $model_dictionary = $model_dictionary_collection::getRuleClassName(); + $model_entry = [ + 'title' => $definition->getAssetModelClassName()::getTypeName(Session::getPluralNumber()), + 'page' => $model_dictionary::getSearchURL(false), + 'links' => [ + 'search' => $model_dictionary::getSearchURL(false) + ] + ]; + if ($model_dictionary::canCreate()) { + $model_entry['links']['add'] = $model_dictionary::getFormURL(false); + } + $menu['dictionnary']['options']['model.' . $definition->fields['system_name']] = $model_entry; + + $type_dictionary_collection = $definition->getAssetTypeDictionaryCollectionClassName(); + $type_dictionary = $type_dictionary_collection::getRuleClassName(); + $type_entry = [ + 'title' => $definition->getAssetTypeClassName()::getTypeName(Session::getPluralNumber()), + 'page' => $type_dictionary::getSearchURL(false), + 'links' => [ + 'search' => $type_dictionary::getSearchURL(false) + ] + ]; + if ($type_dictionary::canCreate()) { + $type_entry['links']['add'] = $type_dictionary::getFormURL(false); + } + $menu['dictionnary']['options']['type.' . $definition->fields['system_name']] = $type_entry; + } + if (count($menu)) { $menu['is_multi_entries'] = true; return $menu; diff --git a/src/RuleCollection.php b/src/RuleCollection.php index 1c166e38b8e..891fdfb31a5 100644 --- a/src/RuleCollection.php +++ b/src/RuleCollection.php @@ -156,7 +156,7 @@ public function getRuleListCriteria($options = []) } //Select all the rules of a different type - $where['sub_type'] = $this->getRuleClassName(); + $where['sub_type'] = static::getRuleClassName(); if ($this->isRuleRecursive()) { $criteria['LEFT JOIN'] = [ Entity::getTable() => [ @@ -259,7 +259,7 @@ public function getCollectionDatas($retrieve_criteria = 0, $retrieve_action = 0, if ($this->RuleList === null) { $this->RuleList = SingletonRuleList::getInstance( - $this->getRuleClassName(), + static::getRuleClassName(), $this->entity ); } @@ -299,7 +299,7 @@ public function getCollectionDatas($retrieve_criteria = 0, $retrieve_action = 0, /** * @return class-string|string class-string if valid; else empty string */ - public function getRuleClassName() + public static function getRuleClassName() { if (preg_match('/(.*)Collection/', static::class, $rule_class)) { return $rule_class[1]; @@ -313,7 +313,7 @@ public function getRuleClassName() **/ public function getRuleClass() { - $name = $this->getRuleClassName(); + $name = static::getRuleClassName(); if ($name !== '') { return new $name(); } @@ -502,7 +502,7 @@ public function showListRules($target, $options = []) $p['limit'] = $_SESSION['glpilist_limit']; $this->getCollectionPart($p); - $ruletype = $this->getRuleClassName(); + $ruletype = static::getRuleClassName(); $entries = []; for ($i = $p['start'],$j = 0; isset($this->RuleList->list[$j]); $i++,$j++) { @@ -559,7 +559,7 @@ public function showListRules($target, $options = []) 'extraparams' => [ 'entity' => $this->entity, 'condition' => $p['condition'], - 'rule_class_name' => $this->getRuleClassName() + 'rule_class_name' => static::getRuleClassName() ], 'item' => $this ] @@ -685,7 +685,7 @@ public function changeRuleOrder($ID, $action, $condition = 0) 'SELECT' => ['id', 'ranking'], 'FROM' => 'glpi_rules', 'WHERE' => [ - 'sub_type' => $this->getRuleClassName() + 'sub_type' => static::getRuleClassName() ] + $add_condition, 'LIMIT' => 1 ]; @@ -718,7 +718,7 @@ public function changeRuleOrder($ID, $action, $condition = 0) $criteria = [ 'SELECT' => ['id', 'ranking'], 'FROM' => 'glpi_rules', - 'WHERE' => ['sub_type' => $this->getRuleClassName()] + 'WHERE' => ['sub_type' => static::getRuleClassName()] ]; $diff = $new_rank - $current_rank; switch ($action) { @@ -794,7 +794,7 @@ public function deleteRuleOrder($ranking) 'ranking' => new QueryExpression($DB::quoteName('ranking') . ' - 1') ], [ - 'sub_type' => $this->getRuleClassName(), + 'sub_type' => static::getRuleClassName(), 'ranking' => ['>', $ranking] ] ); @@ -824,7 +824,7 @@ public function moveRule($ID, $ref_ID, $type = self::MOVE_AFTER, $new_rule = fal $max_ranking_criteria = [ 'SELECT' => ['MAX' => 'ranking AS maxi'], 'FROM' => 'glpi_rules', - 'WHERE' => ['sub_type' => $this->getRuleClassName()] + 'WHERE' => ['sub_type' => static::getRuleClassName()] ]; if (is_numeric($type)) { @@ -870,7 +870,7 @@ public function moveRule($ID, $ref_ID, $type = self::MOVE_AFTER, $new_rule = fal 'SELECT' => ['id', 'ranking AS _ranking'], 'FROM' => 'glpi_rules', 'WHERE' => [ - 'sub_type' => $this->getRuleClassName(), + 'sub_type' => static::getRuleClassName(), ['ranking' => ['>', $old_rank]], ['ranking' => ['<=', $rank]] ] @@ -889,7 +889,7 @@ public function moveRule($ID, $ref_ID, $type = self::MOVE_AFTER, $new_rule = fal 'SELECT' => ['id', 'ranking AS _ranking'], 'FROM' => 'glpi_rules', 'WHERE' => [ - 'sub_type' => $this->getRuleClassName(), + 'sub_type' => static::getRuleClassName(), ['ranking' => ['>=', $rank]], ['ranking' => ['<', $old_rank]] ] @@ -1441,7 +1441,7 @@ public function processAllRules($input = [], $output = [], $params = [], $option $output["_no_rule_matches"] = true; //Store rule type being processed (for plugins) - $params['rule_itemtype'] = $this->getRuleClassName(); + $params['rule_itemtype'] = static::getRuleClassName(); if (count($this->RuleList->list)) { foreach ($this->RuleList->list as $rule) { @@ -1509,7 +1509,7 @@ public function showRulesEnginePreviewCriteriasForm($target, array $values, $con 'input' => $input, 'values' => $values, 'criteria' => $criterias, - 'rule_classname' => $this->getRuleClassName(), + 'rule_classname' => static::getRuleClassName(), 'condition' => $condition, 'params' => [ 'target' => $target, @@ -1604,11 +1604,11 @@ public function prepareInputDataForProcessWithPlugins($input, $params) if (!Plugin::isPluginActive($plugin)) { continue; } - if (is_array($val) && in_array($this->getRuleClassName(), $val, true)) { + if (is_array($val) && in_array(static::getRuleClassName(), $val, true)) { $results = Plugin::doOneHook( $plugin, 'ruleCollectionPrepareInputDataForProcess', - ['rule_itemtype' => $this->getRuleClassName(), + ['rule_itemtype' => static::getRuleClassName(), 'values' => ['input' => $input, 'params' => $params ] @@ -1657,7 +1657,7 @@ public function prepareInputDataForTestProcess($condition = 0) ], 'WHERE' => [ 'glpi_rules.is_active' => 1, - 'glpi_rules.sub_type' => $this->getRuleClassName() + 'glpi_rules.sub_type' => static::getRuleClassName() ] + $limit ]); @@ -1876,7 +1876,7 @@ public function getFieldsToLookFor() ], 'WHERE' => [ 'glpi_rules.is_active' => 1, - 'glpi_rules.sub_type' => $this->getRuleClassName() + 'glpi_rules.sub_type' => static::getRuleClassName() ] ]); @@ -2076,8 +2076,10 @@ public static function getDictionnaries(): array ]; } + $custom_assets = \Glpi\Asset\AssetDefinitionManager::getInstance()->getDefinitions(true); + if (Session::haveRight("rule_dictionnary_dropdown", READ)) { - $dictionnaries[] = [ + $model_dictionaries = [ 'type' => _n('Model', 'Models', Session::getPluralNumber()), 'entries' => [ [ @@ -2107,10 +2109,21 @@ public static function getDictionnaries(): array ] ] ]; + + foreach ($custom_assets as $custom_asset) { + $model_class = $custom_asset->getAssetModelClassName(); + $model_dictionaries['entries'][] = [ + 'label' => $model_class::getTypeName(Session::getPluralNumber()), + 'link' => $custom_asset->getAssetModelDictionaryCollectionClassName()::getRuleClassName()::getSearchURL(), + 'icon' => $model_class::getIcon(), + ]; + } + + $dictionnaries[] = $model_dictionaries; } if (Session::haveRight("rule_dictionnary_dropdown", READ)) { - $dictionnaries[] = [ + $type_dictionaries = [ 'type' => _n('Type', 'Types', Session::getPluralNumber()), 'entries' => [ [ @@ -2140,6 +2153,17 @@ public static function getDictionnaries(): array ] ] ]; + + foreach ($custom_assets as $custom_asset) { + $type_class = $custom_asset->getAssetTypeClassName(); + $type_dictionaries['entries'][] = [ + 'label' => $type_class::getTypeName(Session::getPluralNumber()), + 'link' => $custom_asset->getAssetTypeDictionaryCollectionClassName()::getRuleClassName()::getSearchURL(), + 'icon' => $type_class::getIcon(), + ]; + } + + $dictionnaries[] = $type_dictionaries; } if (Session::haveRight("rule_dictionnary_dropdown", READ)) { diff --git a/src/RuleCommonITILObjectCollection.php b/src/RuleCommonITILObjectCollection.php index 4b20ed19bff..25264c64b99 100644 --- a/src/RuleCommonITILObjectCollection.php +++ b/src/RuleCommonITILObjectCollection.php @@ -61,7 +61,7 @@ public static function getItemtype(): string public static function canView(): bool { - $rule_class = (new static())->getRuleClassName(); + $rule_class = static::getRuleClassName(); return Session::haveRightsOr(static::$rightname, [READ, $rule_class::PARENT]); } @@ -80,7 +80,7 @@ public function preProcessPreviewResults($output) public function showInheritedTab() { - $rule_class = $this->getRuleClassName(); + $rule_class = static::getRuleClassName(); return (Session::haveRight(self::$rightname, $rule_class::PARENT) && ($this->entity)); } diff --git a/src/RuleDictionnaryDropdownCollection.php b/src/RuleDictionnaryDropdownCollection.php index 62a28bf4cfc..905df1b296b 100644 --- a/src/RuleDictionnaryDropdownCollection.php +++ b/src/RuleDictionnaryDropdownCollection.php @@ -268,7 +268,7 @@ public function replayRulesOnExistingDBForModel($offset = 0, $maxtime = 0) } // Manage cartridge assoc Update items - if ($this->getRuleClassName() === RuleDictionnaryPrinterModel::class) { + if (static::getRuleClassName() === RuleDictionnaryPrinterModel::class) { $iterator2 = $DB->request([ 'FROM' => 'glpi_cartridgeitems_printermodels', 'WHERE' => ['printermodels_id' => $ID] From b66eb4b4f4143f4eb1ad9e0fc129981f085f9110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Mon, 16 Sep 2024 11:13:49 +0200 Subject: [PATCH 2/7] revert useless changes --- phpunit/DbTestCase.php | 10 ++++++++-- phpunit/functional/HtmlTest.php | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/phpunit/DbTestCase.php b/phpunit/DbTestCase.php index 136387e34b1..78406754e6a 100644 --- a/phpunit/DbTestCase.php +++ b/phpunit/DbTestCase.php @@ -348,8 +348,14 @@ protected function initAssetDefinition( ], skip_fields: ['capacities', 'profiles'] // JSON encoded fields cannot be automatically checked ); - $this->assertEquals($capacities, $this->callPrivateMethod($definition, 'getDecodedCapacitiesField')); - $this->assertEquals($profiles, $this->callPrivateMethod($definition, 'getDecodedProfilesField')); + $this->assertEquals( + $capacities, + $this->callPrivateMethod($definition, 'getDecodedCapacitiesField') + ); + $this->assertEquals( + $profiles, + $this->callPrivateMethod($definition, 'getDecodedProfilesField') + ); $manager = AssetDefinitionManager::getInstance(); $this->callPrivateMethod($manager, 'loadConcreteClass', $definition); diff --git a/phpunit/functional/HtmlTest.php b/phpunit/functional/HtmlTest.php index 3a832816fb6..5fc6bbd3897 100644 --- a/phpunit/functional/HtmlTest.php +++ b/phpunit/functional/HtmlTest.php @@ -270,7 +270,7 @@ public function testGetMenuInfos() 'Item_DeviceSimcard' ]; $this->assertSame('Assets', $menu['assets']['title']); - $this->assertSame($expected, array_intersect($expected, $menu['assets']['types'])); + $this->assertSame($expected, $menu['assets']['types']); $expected = [ 'Ticket', From b160885ed6359a9f28e693e59deed2ef7e315b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Mon, 16 Sep 2024 12:05:05 +0200 Subject: [PATCH 3/7] Move abstract code into abstract classes --- src/Glpi/Asset/AssetDefinition.php | 34 ++++- src/Glpi/Asset/AssetDefinitionManager.php | 131 ++++-------------- src/Glpi/Asset/RuleDictionaryModel.php | 107 ++++++++++++++ .../Asset/RuleDictionaryModelCollection.php | 74 ++++++++++ src/Glpi/Asset/RuleDictionaryType.php | 101 ++++++++++++++ .../Asset/RuleDictionaryTypeCollection.php | 74 ++++++++++ 6 files changed, 416 insertions(+), 105 deletions(-) create mode 100644 src/Glpi/Asset/RuleDictionaryModel.php create mode 100644 src/Glpi/Asset/RuleDictionaryModelCollection.php create mode 100644 src/Glpi/Asset/RuleDictionaryType.php create mode 100644 src/Glpi/Asset/RuleDictionaryTypeCollection.php diff --git a/src/Glpi/Asset/AssetDefinition.php b/src/Glpi/Asset/AssetDefinition.php index 1edc5f25163..d6a6efee921 100644 --- a/src/Glpi/Asset/AssetDefinition.php +++ b/src/Glpi/Asset/AssetDefinition.php @@ -895,6 +895,21 @@ public function getAssetTypeClassName(bool $with_namespace = true): string return $this->getAssetClassName($with_namespace) . 'Type'; } + /** + * Get the definition's concrete asset model dictionary class name. + * + * @param bool $with_namespace + * @return class-string + */ + public function getAssetModelDictionaryClassName(bool $with_namespace = true): string + { + $classname = 'RuleDictionary' . $this->getAssetModelClassName(false); + if ($with_namespace) { + $classname = 'Glpi\\CustomAsset\\' . $classname; + } + return $classname; + } + /** * Get the definition's concrete asset model dictionary collection class name. * @@ -903,7 +918,22 @@ public function getAssetTypeClassName(bool $with_namespace = true): string */ public function getAssetModelDictionaryCollectionClassName(bool $with_namespace = true): string { - $classname = 'RuleDictionary' . $this->getAssetModelClassName(false) . 'Collection'; + $classname = $this->getAssetModelDictionaryClassName(false) . 'Collection'; + if ($with_namespace) { + $classname = 'Glpi\\CustomAsset\\' . $classname; + } + return $classname; + } + + /** + * Get the definition's concrete asset type dictionary class name. + * + * @param bool $with_namespace + * @return class-string + */ + public function getAssetTypeDictionaryClassName(bool $with_namespace = true): string + { + $classname = 'RuleDictionary' . $this->getAssetTypeClassName(false); if ($with_namespace) { $classname = 'Glpi\\CustomAsset\\' . $classname; } @@ -918,7 +948,7 @@ public function getAssetModelDictionaryCollectionClassName(bool $with_namespace */ public function getAssetTypeDictionaryCollectionClassName(bool $with_namespace = true): string { - $classname = 'RuleDictionary' . $this->getAssetTypeClassName(false) . 'Collection'; + $classname = $this->getAssetTypeDictionaryClassName(false) . 'Collection'; if ($with_namespace) { $classname = 'Glpi\\CustomAsset\\' . $classname; } diff --git a/src/Glpi/Asset/AssetDefinitionManager.php b/src/Glpi/Asset/AssetDefinitionManager.php index 54c2b0c9d79..20b11b9c19b 100644 --- a/src/Glpi/Asset/AssetDefinitionManager.php +++ b/src/Glpi/Asset/AssetDefinitionManager.php @@ -458,58 +458,21 @@ final class {$definition->getAssetTypeClassName(false)} extends AssetType { private function loadConcreteModelDictionaryClass(AssetDefinition $definition): void { - $model_class = $definition->getAssetModelClassName(); eval(<<getAssetModelClassName(false)} extends RuleDictionnaryDropdown +final class {$definition->getAssetModelDictionaryClassName(false)} extends RuleDictionaryModel { - public function getCriterias() - { - static \$criterias = []; - - if (count(\$criterias)) { - return \$criterias; - } - - \$criterias['name']['field'] = 'name'; - \$criterias['name']['name'] = _n('Model', 'Models', 1); - \$criterias['name']['table'] = '{$model_class::getTable()}'; - - \$criterias['manufacturer']['field'] = 'name'; - \$criterias['manufacturer']['name'] = Manufacturer::getTypeName(1); - \$criterias['manufacturer']['table'] = 'glpi_manufacturers'; - - return \$criterias; - } - - public function getActions() - { - \$actions = []; - \$actions['name']['name'] = _n('Model', 'Models', 1); - \$actions['name']['force_actions'] = ['append_regex_result', 'assign', 'regex_result']; - - return \$actions; - } - - public static function getSearchURL(\$full = true) - { - /** @var array \$CFG_GLPI */ - global \$CFG_GLPI; - return (\$full ? \$CFG_GLPI['root_doc'] : '') . '/front/asset/ruledictionarymodel.php?class={$definition->fields['system_name']}'; - } - - public static function getFormURL(\$full = true) - { - /** @var array \$CFG_GLPI */ - global \$CFG_GLPI; - return (\$full ? \$CFG_GLPI['root_doc'] : '') . '/front/asset/ruledictionarymodel.form.php?class={$definition->fields['system_name']}'; - } + protected static AssetDefinition \$definition; } PHP ); + + $reflected_class = new ReflectionClass($definition->getAssetModelDictionaryClassName()); + $reflected_class->setStaticPropertyValue('definition', $definition); } private function loadConcreteTypeDictionaryClass(AssetDefinition $definition): void @@ -517,93 +480,55 @@ private function loadConcreteTypeDictionaryClass(AssetDefinition $definition): v eval(<<getAssetTypeClassName(false)} extends RuleDictionnaryDropdown +final class {$definition->getAssetTypeDictionaryClassName(false)} extends RuleDictionaryType { - public function getCriterias() - { - static \$criterias = []; - - if (count(\$criterias)) { - return \$criterias; - } - - \$criterias['name']['field'] = 'name'; - \$criterias['name']['name'] = _n('Type', 'Types', 1); - \$criterias['name']['table'] = '{$definition->getAssetTypeClassName()::getTable()}'; - - return \$criterias; - } - - public function getActions() - { - \$actions = []; - \$actions['name']['name'] = _n('Type', 'Types', 1); - \$actions['name']['force_actions'] = ['append_regex_result', 'assign','regex_result']; - - return \$actions; - } - - public static function getSearchURL(\$full = true) - { - /** @var array \$CFG_GLPI */ - global \$CFG_GLPI; - return (\$full ? \$CFG_GLPI['root_doc'] : '') . '/front/asset/ruledictionarytype.php?class={$definition->fields['system_name']}'; - } - - public static function getFormURL(\$full = true) - { - /** @var array \$CFG_GLPI */ - global \$CFG_GLPI; - return (\$full ? \$CFG_GLPI['root_doc'] : '') . '/front/asset/ruledictionarytype.form.php?class={$definition->fields['system_name']}'; - } + protected static AssetDefinition \$definition; } PHP ); + + $reflected_class = new ReflectionClass($definition->getAssetTypeDictionaryClassName()); + $reflected_class->setStaticPropertyValue('definition', $definition); } private function loadConcreteModelDictionaryCollectionClass(AssetDefinition $definition): void { - $model_class = $definition->getAssetModelClassName(); eval(<<getAssetModelClassName(false)}Collection extends RuleDictionnaryDropdownCollection +final class {$definition->getAssetModelDictionaryCollectionClassName(false)} extends RuleDictionaryModelCollection { - public \$item_table = '{$model_class::getTable()}'; - public \$menu_option = "model.{$definition->fields['system_name']}"; - - public function getTitle() - { - return sprintf(__('Dictionary of %s'), '{$model_class::getTypeName()}'); - } + protected static AssetDefinition \$definition; } PHP ); + + $reflected_class = new ReflectionClass($definition->getAssetModelDictionaryCollectionClassName()); + $reflected_class->setStaticPropertyValue('definition', $definition); } private function loadConcreteTypeDictionaryCollectionClass(AssetDefinition $definition): void { - $type_class = $definition->getAssetTypeClassName(); eval(<<getAssetTypeClassName(false)}Collection extends RuleDictionnaryDropdownCollection +final class {$definition->getAssetTypeDictionaryCollectionClassName(false)} extends RuleDictionaryTypeCollection { - public \$item_table = '{$type_class::getTable()}'; - public \$menu_option = "model.{$definition->fields['system_name']}"; - - public function getTitle() - { - return sprintf(__('Dictionary of %s'), '{$type_class::getTypeName()}'); - } + protected static AssetDefinition \$definition; } PHP ); + + $reflected_class = new ReflectionClass($definition->getAssetTypeDictionaryCollectionClassName()); + $reflected_class->setStaticPropertyValue('definition', $definition); } } diff --git a/src/Glpi/Asset/RuleDictionaryModel.php b/src/Glpi/Asset/RuleDictionaryModel.php new file mode 100644 index 00000000000..8c9858e2b80 --- /dev/null +++ b/src/Glpi/Asset/RuleDictionaryModel.php @@ -0,0 +1,107 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace Glpi\Asset; + +use Manufacturer; +use RuleDictionnaryDropdown; +use Toolbox; + +abstract class RuleDictionaryModel extends RuleDictionnaryDropdown +{ + /** + * Asset definition. + * + * Must be defined here to make PHPStan happy (see https://github.com/phpstan/phpstan/issues/8808). + * Must be defined by child class too to ensure that assigning a value to this property will affect + * each child classe independently. + */ + protected static AssetDefinition $definition; + + /** + * Get the asset definition related to concrete class. + * + * @return AssetDefinition + */ + public static function getDefinition(): AssetDefinition + { + if (!(static::$definition instanceof AssetDefinition)) { + throw new \RuntimeException('Asset definition is expected to be defined in concrete class.'); + } + + return static::$definition; + } + + public function getCriterias() + { + return [ + 'name' => [ + 'field' => 'name', + 'name' => _n('Model', 'Models', 1), + 'table' => static::getDefinition()->getAssetModelClassName()::getTable(), + ], + 'manufacturer' => [ + 'field' => 'name', + 'name' => Manufacturer::getTypeName(1), + 'table' => Manufacturer::getTable(), + ], + ]; + } + + public function getActions() + { + return [ + 'name' => [ + 'name' => _n('Model', 'Models', 1), + 'force_actions' => [ + 'append_regex_result', + 'assign', + 'regex_result', + ], + ], + ]; + } + + public static function getSearchURL($full = true) + { + return Toolbox::getItemTypeSearchURL(self::class, $full) + . '?class=' . static::getDefinition()->getAssetClassName(false); + } + + public static function getFormURL($full = true) + { + return Toolbox::getItemTypeFormURL(self::class, $full) + . '?class=' . static::getDefinition()->getAssetClassName(false); + } +} diff --git a/src/Glpi/Asset/RuleDictionaryModelCollection.php b/src/Glpi/Asset/RuleDictionaryModelCollection.php new file mode 100644 index 00000000000..3952932a942 --- /dev/null +++ b/src/Glpi/Asset/RuleDictionaryModelCollection.php @@ -0,0 +1,74 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace Glpi\Asset; + +use RuleDictionnaryDropdownCollection; + +abstract class RuleDictionaryModelCollection extends RuleDictionnaryDropdownCollection +{ + /** + * Asset definition. + * + * Must be defined here to make PHPStan happy (see https://github.com/phpstan/phpstan/issues/8808). + * Must be defined by child class too to ensure that assigning a value to this property will affect + * each child classe independently. + */ + protected static AssetDefinition $definition; + + /** + * Get the asset definition related to concrete class. + * + * @return AssetDefinition + */ + public static function getDefinition(): AssetDefinition + { + if (!(static::$definition instanceof AssetDefinition)) { + throw new \RuntimeException('Asset definition is expected to be defined in concrete class.'); + } + + return static::$definition; + } + + public function __construct() + { + $this->item_table = static::getDefinition()->getAssetModelClassName()::getTable(); + $this->menu_option = sprintf('model.%s', static::getDefinition()->fields['system_name']); + } + + public function getTitle() + { + return sprintf(__('Dictionary of %s'), static::getDefinition()->getAssetModelClassName()::getTypeName()); + } +} diff --git a/src/Glpi/Asset/RuleDictionaryType.php b/src/Glpi/Asset/RuleDictionaryType.php new file mode 100644 index 00000000000..0e0132f5527 --- /dev/null +++ b/src/Glpi/Asset/RuleDictionaryType.php @@ -0,0 +1,101 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace Glpi\Asset; + +use RuleDictionnaryDropdown; +use Toolbox; + +abstract class RuleDictionaryType extends RuleDictionnaryDropdown +{ + /** + * Asset definition. + * + * Must be defined here to make PHPStan happy (see https://github.com/phpstan/phpstan/issues/8808). + * Must be defined by child class too to ensure that assigning a value to this property will affect + * each child classe independently. + */ + protected static AssetDefinition $definition; + + /** + * Get the asset definition related to concrete class. + * + * @return AssetDefinition + */ + public static function getDefinition(): AssetDefinition + { + if (!(static::$definition instanceof AssetDefinition)) { + throw new \RuntimeException('Asset definition is expected to be defined in concrete class.'); + } + + return static::$definition; + } + + public function getCriterias() + { + return [ + 'name' => [ + 'field' => 'name', + 'name' => _n('Type', 'Types', 1), + 'table' => static::getDefinition()->getAssetTypeClassName()::getTable(), + ], + ]; + } + + public function getActions() + { + return [ + 'name' => [ + 'name' => _n('Type', 'Types', 1), + 'force_actions' => [ + 'append_regex_result', + 'assign', + 'regex_result', + ], + ], + ]; + } + + public static function getSearchURL($full = true) + { + return Toolbox::getItemTypeSearchURL(self::class, $full) + . '?class=' . static::getDefinition()->getAssetClassName(false); + } + + public static function getFormURL($full = true) + { + return Toolbox::getItemTypeFormURL(self::class, $full) + . '?class=' . static::getDefinition()->getAssetClassName(false); + } +} diff --git a/src/Glpi/Asset/RuleDictionaryTypeCollection.php b/src/Glpi/Asset/RuleDictionaryTypeCollection.php new file mode 100644 index 00000000000..0f77560e25a --- /dev/null +++ b/src/Glpi/Asset/RuleDictionaryTypeCollection.php @@ -0,0 +1,74 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace Glpi\Asset; + +use RuleDictionnaryDropdownCollection; + +abstract class RuleDictionaryTypeCollection extends RuleDictionnaryDropdownCollection +{ + /** + * Asset definition. + * + * Must be defined here to make PHPStan happy (see https://github.com/phpstan/phpstan/issues/8808). + * Must be defined by child class too to ensure that assigning a value to this property will affect + * each child classe independently. + */ + protected static AssetDefinition $definition; + + /** + * Get the asset definition related to concrete class. + * + * @return AssetDefinition + */ + public static function getDefinition(): AssetDefinition + { + if (!(static::$definition instanceof AssetDefinition)) { + throw new \RuntimeException('Asset definition is expected to be defined in concrete class.'); + } + + return static::$definition; + } + + public function __construct() + { + $this->item_table = static::getDefinition()->getAssetTypeClassName()::getTable(); + $this->menu_option = sprintf('model.%s', static::getDefinition()->fields['system_name']); + } + + public function getTitle() + { + return sprintf(__('Dictionary of %s'), static::getDefinition()->getAssetTypeClassName()::getTypeName()); + } +} From f2c51f40863ccc8fa3c9181348ecff056ccdd803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Mon, 16 Sep 2024 12:05:13 +0200 Subject: [PATCH 4/7] Fix redirect --- front/rule.common.form.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/rule.common.form.php b/front/rule.common.form.php index 3e2a03c7e08..af0ef43123b 100644 --- a/front/rule.common.form.php +++ b/front/rule.common.form.php @@ -77,7 +77,7 @@ "setup", sprintf(__('%1$s adds the item %2$s'), $_SESSION["glpiname"], $newID) ); - Html::redirect($_SERVER['HTTP_REFERER'] . "?id=$newID"); + Html::redirect($rule->getFormURLWithID($newID)); } else if (isset($_POST["purge"])) { $rulecollection->checkGlobal(PURGE); $rulecollection->deleteRuleOrder($_POST["ranking"]); From 9c0ef97fe7b8b86a5c64778cadac0707872fab4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Mon, 16 Sep 2024 12:20:36 +0200 Subject: [PATCH 5/7] fix lint --- .phpstan-baseline.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.phpstan-baseline.php b/.phpstan-baseline.php index c414771bee8..d26b10496ce 100644 --- a/.phpstan-baseline.php +++ b/.phpstan-baseline.php @@ -2019,13 +2019,13 @@ ]; $ignoreErrors[] = [ // identifier: return.type - 'message' => '#^Method Glpi\\\\Asset\\\\AssetModel\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\AssetModel\\)\\|false but returns object\\.$#', + 'message' => '#^Method Glpi\\\\Asset\\\\AssetModel\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\AssetModel\\)\\|false but returns CommonDBTM\\.$#', 'count' => 1, 'path' => __DIR__ . '/src/Glpi/Asset/AssetModel.php', ]; $ignoreErrors[] = [ // identifier: return.type - 'message' => '#^Method Glpi\\\\Asset\\\\AssetType\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\AssetType\\)\\|false but returns object\\.$#', + 'message' => '#^Method Glpi\\\\Asset\\\\AssetType\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\AssetType\\)\\|false but returns CommonDBTM\\.$#', 'count' => 1, 'path' => __DIR__ . '/src/Glpi/Asset/AssetType.php', ]; From 46a01ec8ad8eca17c5f45d96e4090c9e73409eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Mon, 16 Sep 2024 12:25:51 +0200 Subject: [PATCH 6/7] Fix PHPDoc --- .phpstan-baseline.php | 72 ++---------------------------- front/asset/asset.form.php | 3 ++ src/Glpi/Asset/AssetDefinition.php | 20 ++++++--- 3 files changed, 19 insertions(+), 76 deletions(-) diff --git a/.phpstan-baseline.php b/.phpstan-baseline.php index d26b10496ce..c38b7f0182b 100644 --- a/.phpstan-baseline.php +++ b/.phpstan-baseline.php @@ -1,72 +1,6 @@ '#^Cannot access constant class on object\\|false\\.$#', - 'count' => 6, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; -$ignoreErrors[] = [ - // identifier: staticProperty.nonObject - 'message' => '#^Cannot access static property \\$rightname on object\\|false\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; -$ignoreErrors[] = [ - // identifier: method.nonObject - 'message' => '#^Cannot call method add\\(\\) on object\\|false\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; -$ignoreErrors[] = [ - // identifier: method.nonObject - 'message' => '#^Cannot call method check\\(\\) on object\\|false\\.$#', - 'count' => 5, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; -$ignoreErrors[] = [ - // identifier: method.nonObject - 'message' => '#^Cannot call method delete\\(\\) on object\\|false\\.$#', - 'count' => 2, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; -$ignoreErrors[] = [ - // identifier: method.nonObject - 'message' => '#^Cannot call method getLinkURL\\(\\) on object\\|false\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; -$ignoreErrors[] = [ - // identifier: method.nonObject - 'message' => '#^Cannot call method redirectToList\\(\\) on object\\|false\\.$#', - 'count' => 3, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; -$ignoreErrors[] = [ - // identifier: method.nonObject - 'message' => '#^Cannot call method restore\\(\\) on object\\|false\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; -$ignoreErrors[] = [ - // identifier: method.nonObject - 'message' => '#^Cannot call method update\\(\\) on object\\|false\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; -$ignoreErrors[] = [ - // identifier: staticMethod.nonObject - 'message' => '#^Cannot call static method displayFullPageForItem\\(\\) on object\\|false\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; -$ignoreErrors[] = [ - // identifier: staticMethod.nonObject - 'message' => '#^Cannot call static method getDefinition\\(\\) on object\\|false\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/front/asset/asset.form.php', -]; $ignoreErrors[] = [ // identifier: booleanOr.alwaysFalse 'message' => '#^Result of \\|\\| is always false\\.$#', @@ -2001,7 +1935,7 @@ ]; $ignoreErrors[] = [ // identifier: return.type - 'message' => '#^Method Glpi\\\\Asset\\\\Asset\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\Asset\\)\\|false but returns object\\.$#', + 'message' => '#^Method Glpi\\\\Asset\\\\Asset\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\Asset\\)\\|false but returns Glpi\\\\Asset\\\\Asset\\.$#', 'count' => 1, 'path' => __DIR__ . '/src/Glpi/Asset/Asset.php', ]; @@ -2019,13 +1953,13 @@ ]; $ignoreErrors[] = [ // identifier: return.type - 'message' => '#^Method Glpi\\\\Asset\\\\AssetModel\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\AssetModel\\)\\|false but returns CommonDBTM\\.$#', + 'message' => '#^Method Glpi\\\\Asset\\\\AssetModel\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\AssetModel\\)\\|false but returns Glpi\\\\Asset\\\\AssetModel\\.$#', 'count' => 1, 'path' => __DIR__ . '/src/Glpi/Asset/AssetModel.php', ]; $ignoreErrors[] = [ // identifier: return.type - 'message' => '#^Method Glpi\\\\Asset\\\\AssetType\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\AssetType\\)\\|false but returns CommonDBTM\\.$#', + 'message' => '#^Method Glpi\\\\Asset\\\\AssetType\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\AssetType\\)\\|false but returns Glpi\\\\Asset\\\\AssetType\\.$#', 'count' => 1, 'path' => __DIR__ . '/src/Glpi/Asset/AssetType.php', ]; diff --git a/front/asset/asset.form.php b/front/asset/asset.form.php index 04a346649ab..f68cc25abca 100644 --- a/front/asset/asset.form.php +++ b/front/asset/asset.form.php @@ -44,6 +44,9 @@ if (array_key_exists('id', $_REQUEST) && !Asset::isNewId($_REQUEST['id'])) { $asset = Asset::getById($_REQUEST['id']); + if ($asset === false) { + $asset = null; + } } else { $definition = new AssetDefinition(); $classname = array_key_exists('class', $_GET) && $definition->getFromDBBySystemName((string)$_GET['class']) diff --git a/src/Glpi/Asset/AssetDefinition.php b/src/Glpi/Asset/AssetDefinition.php index d6a6efee921..c7c0deb0c34 100644 --- a/src/Glpi/Asset/AssetDefinition.php +++ b/src/Glpi/Asset/AssetDefinition.php @@ -48,7 +48,6 @@ use Glpi\Search\SearchOption; use Profile; use ProfileRight; -use RuleDictionnaryDropdownCollection; use Session; final class AssetDefinition extends CommonDBTM @@ -861,6 +860,7 @@ public static function getSpecificValueToSelect($field, $name = '', $values = '' * * @param bool $with_namespace * @return string + * @phpstan-return class-string<\Glpi\Asset\Asset> */ public function getAssetClassName(bool $with_namespace = true): string { @@ -877,7 +877,8 @@ public function getAssetClassName(bool $with_namespace = true): string * Get the definition's concrete asset model class name. * * @param bool $with_namespace - * @return class-string + * @return string + * @phpstan-return class-string<\Glpi\Asset\AssetModel> */ public function getAssetModelClassName(bool $with_namespace = true): string { @@ -888,7 +889,8 @@ public function getAssetModelClassName(bool $with_namespace = true): string * Get the definition's concrete asset type class name. * * @param bool $with_namespace - * @return class-string + * @return string + * @phpstan-return class-string<\Glpi\Asset\AssetType> */ public function getAssetTypeClassName(bool $with_namespace = true): string { @@ -899,7 +901,8 @@ public function getAssetTypeClassName(bool $with_namespace = true): string * Get the definition's concrete asset model dictionary class name. * * @param bool $with_namespace - * @return class-string + * @return string + * @phpstan-return class-string<\Glpi\Asset\RuleDictionaryModel> */ public function getAssetModelDictionaryClassName(bool $with_namespace = true): string { @@ -914,7 +917,8 @@ public function getAssetModelDictionaryClassName(bool $with_namespace = true): s * Get the definition's concrete asset model dictionary collection class name. * * @param bool $with_namespace - * @return class-string + * @return string + * @phpstan-return class-string<\Glpi\Asset\RuleDictionaryModelCollection> */ public function getAssetModelDictionaryCollectionClassName(bool $with_namespace = true): string { @@ -929,7 +933,8 @@ public function getAssetModelDictionaryCollectionClassName(bool $with_namespace * Get the definition's concrete asset type dictionary class name. * * @param bool $with_namespace - * @return class-string + * @return string + * @phpstan-return class-string<\Glpi\Asset\RuleDictionaryType> */ public function getAssetTypeDictionaryClassName(bool $with_namespace = true): string { @@ -944,7 +949,8 @@ public function getAssetTypeDictionaryClassName(bool $with_namespace = true): st * Get the definition's concrete asset type dictionary collection class name. * * @param bool $with_namespace - * @return class-string + * @return string + * @phpstan-return class-string<\Glpi\Asset\RuleDictionaryTypeCollection> */ public function getAssetTypeDictionaryCollectionClassName(bool $with_namespace = true): string { From 4e822fb238a8fa3be2696baf0652c3577091dcf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Mon, 16 Sep 2024 13:52:37 +0200 Subject: [PATCH 7/7] Fix tests --- phpunit/DbTestCase.php | 14 +++++++++----- tests/DbTestCase.php | 12 ++++++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/phpunit/DbTestCase.php b/phpunit/DbTestCase.php index 78406754e6a..e4928fcfa38 100644 --- a/phpunit/DbTestCase.php +++ b/phpunit/DbTestCase.php @@ -357,16 +357,20 @@ protected function initAssetDefinition( $this->callPrivateMethod($definition, 'getDecodedProfilesField') ); - $manager = AssetDefinitionManager::getInstance(); + // Clear definition cache + $rc = new ReflectionClass(\Glpi\Asset\AssetDefinitionManager::class); + $rc->getProperty('definitions_data')->setValue(\Glpi\Asset\AssetDefinitionManager::getInstance(), null); + + $manager = \Glpi\Asset\AssetDefinitionManager::getInstance(); $this->callPrivateMethod($manager, 'loadConcreteClass', $definition); $this->callPrivateMethod($manager, 'loadConcreteModelClass', $definition); $this->callPrivateMethod($manager, 'loadConcreteTypeClass', $definition); + $this->callPrivateMethod($manager, 'loadConcreteModelDictionaryCollectionClass', $definition); + $this->callPrivateMethod($manager, 'loadConcreteModelDictionaryClass', $definition); + $this->callPrivateMethod($manager, 'loadConcreteTypeDictionaryCollectionClass', $definition); + $this->callPrivateMethod($manager, 'loadConcreteTypeDictionaryClass', $definition); $this->callPrivateMethod($manager, 'boostrapConcreteClass', $definition); - // Clear definition cache - $rc = new ReflectionClass(AssetDefinitionManager::class); - $rc->getProperty('definitions_data')->setValue(AssetDefinitionManager::getInstance(), null); - return $definition; } diff --git a/tests/DbTestCase.php b/tests/DbTestCase.php index 6d5c855f166..c649115cc81 100644 --- a/tests/DbTestCase.php +++ b/tests/DbTestCase.php @@ -351,16 +351,20 @@ protected function initAssetDefinition( $this->array($this->callPrivateMethod($definition, 'getDecodedCapacitiesField'))->isEqualTo($capacities); $this->array($this->callPrivateMethod($definition, 'getDecodedProfilesField'))->isEqualTo($profiles); + // Clear definition cache + $rc = new ReflectionClass(\Glpi\Asset\AssetDefinitionManager::class); + $rc->getProperty('definitions_data')->setValue(\Glpi\Asset\AssetDefinitionManager::getInstance(), null); + $manager = \Glpi\Asset\AssetDefinitionManager::getInstance(); $this->callPrivateMethod($manager, 'loadConcreteClass', $definition); $this->callPrivateMethod($manager, 'loadConcreteModelClass', $definition); $this->callPrivateMethod($manager, 'loadConcreteTypeClass', $definition); + $this->callPrivateMethod($manager, 'loadConcreteModelDictionaryCollectionClass', $definition); + $this->callPrivateMethod($manager, 'loadConcreteModelDictionaryClass', $definition); + $this->callPrivateMethod($manager, 'loadConcreteTypeDictionaryCollectionClass', $definition); + $this->callPrivateMethod($manager, 'loadConcreteTypeDictionaryClass', $definition); $this->callPrivateMethod($manager, 'boostrapConcreteClass', $definition); - // Clear definition cache - $rc = new ReflectionClass(\Glpi\Asset\AssetDefinitionManager::class); - $rc->getProperty('definitions_data')->setValue(\Glpi\Asset\AssetDefinitionManager::getInstance(), null); - return $definition; }