From 9e37a92c11963a5588ae61b2145f5fe601449b99 Mon Sep 17 00:00:00 2001 From: Rom1-B <8530352+Rom1-B@users.noreply.github.com> Date: Tue, 18 Aug 2026 15:55:30 +0200 Subject: [PATCH 1/4] feature/glpi-12.0 --- .github/workflows/continuous-integration.yml | 2 +- CHANGELOG.md | 4 ++++ inc/config.class.php | 4 ++-- inc/tag.class.php | 14 ++++++-------- inc/tagitem.class.php | 12 ++++++------ setup.php | 4 ++-- tests/QuestionTypeTestCase.php | 13 ++++--------- tests/Units/TagDestinationFieldTest.php | 2 +- 8 files changed, 26 insertions(+), 29 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index fbc62738..1e719fe6 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -20,7 +20,7 @@ jobs: name: "Generate CI matrix" uses: "glpi-project/plugin-ci-workflows/.github/workflows/generate-ci-matrix.yml@v1" with: - glpi-version: "11.0.x" + glpi-version: "12.0.x" ci: name: "GLPI ${{ matrix.glpi-version }} - php:${{ matrix.php-version }} - ${{ matrix.db-image }}" needs: "generate-ci-matrix" diff --git a/CHANGELOG.md b/CHANGELOG.md index 04c2e9ad..86bdffe8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +- GLPI 12 compatibility + ### Fixed - CI: fix Psalm cache directory, declare a unique composer autoloader suffix diff --git a/inc/config.class.php b/inc/config.class.php index 8a6e0cbb..361f0030 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -30,7 +30,7 @@ class PluginTagConfig extends CommonDBTM { - protected static $notable = true; + protected static bool $notable = true; public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { @@ -44,7 +44,7 @@ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) public function showConfigForm() { - if (!Session::haveRight('config', UPDATE)) { + if (!Session::haveRight(Config::$rightname, UPDATE)) { return false; } diff --git a/inc/tag.class.php b/inc/tag.class.php index fc1f37db..7518f916 100644 --- a/inc/tag.class.php +++ b/inc/tag.class.php @@ -40,11 +40,11 @@ class PluginTagTag extends CommonDropdown { // From CommonDBTM - public $dohistory = true; + public bool $dohistory = true; public const S_OPTION = 10500; - public static $rightname = 'plugin_tag_tag'; + public static string $rightname = 'plugin_tag_tag'; public static function getTypeName($nb = 1) { @@ -194,11 +194,9 @@ public static function install(Migration $migration) $migration->migrationOneTable($table); $datas = getAllDataFromTable($table, ['NOT' => ['type_menu' => null]]); - if (!empty($datas)) { - foreach ($datas as $data) { - $itemtypes = $CFG_GLPI['plugin_tag_itemtypes'][$data['type_menu']] ?? []; - $DB->update($table, ['type_menu' => json_encode($itemtypes)], ['id' => $data['id']]); - } + foreach ($datas as $data) { + $itemtypes = $CFG_GLPI['plugin_tag_itemtypes'][$data['type_menu']] ?? []; + $DB->update($table, ['type_menu' => json_encode($itemtypes)], ['id' => $data['id']]); } } @@ -924,6 +922,6 @@ public static function getCurrentItemtype() public static function getIcon() { - return "fas fa-tags"; + return "ti ti-tags"; } } diff --git a/inc/tagitem.class.php b/inc/tagitem.class.php index 1b2029c1..6ea954cb 100644 --- a/inc/tagitem.class.php +++ b/inc/tagitem.class.php @@ -65,17 +65,17 @@ class PluginTagTagItem extends CommonDBRelation { // From CommonDBRelation - public static $itemtype_1 = 'PluginTagTag'; + public static ?string $itemtype_1 = 'PluginTagTag'; - public static $items_id_1 = 'plugin_tag_tags_id'; + public static ?string $items_id_1 = 'plugin_tag_tags_id'; - public static $take_entity_1 = true; + public static bool $take_entity_1 = true; - public static $itemtype_2 = 'itemtype'; + public static ?string $itemtype_2 = 'itemtype'; - public static $items_id_2 = 'items_id'; + public static ?string $items_id_2 = 'items_id'; - public static $take_entity_2 = false; + public static bool $take_entity_2 = false; public static function getTypeName($nb = 1) diff --git a/setup.php b/setup.php index 0931f522..e68d5d50 100644 --- a/setup.php +++ b/setup.php @@ -42,9 +42,9 @@ define('PLUGIN_TAG_VERSION', '2.14.8'); // Minimal GLPI version, inclusive -define("PLUGIN_TAG_MIN_GLPI", "11.0.1"); +define("PLUGIN_TAG_MIN_GLPI", "12.0.0"); // Maximum GLPI version, exclusive -define("PLUGIN_TAG_MAX_GLPI", "11.0.99"); +define("PLUGIN_TAG_MAX_GLPI", "12.0.99"); /** * Init hooks of the plugin. diff --git a/tests/QuestionTypeTestCase.php b/tests/QuestionTypeTestCase.php index 444fbe1d..b9d923e6 100644 --- a/tests/QuestionTypeTestCase.php +++ b/tests/QuestionTypeTestCase.php @@ -58,15 +58,10 @@ protected function renderHelpdeskForm(Form $form): Crawler { $this->login(); $controller = new RendererController(); - $response = $controller->__invoke( - Request::create( - '', - 'GET', - [ - 'id' => $form->getID(), - ], - ), - ); + $request = Request::create('', 'GET'); + $request->attributes->set('id', $form->getID()); + + $response = $controller->__invoke($request); return new Crawler($response->getContent()); } } diff --git a/tests/Units/TagDestinationFieldTest.php b/tests/Units/TagDestinationFieldTest.php index 9719900c..781ca25d 100644 --- a/tests/Units/TagDestinationFieldTest.php +++ b/tests/Units/TagDestinationFieldTest.php @@ -44,7 +44,7 @@ use PluginTagTagItem; use User; -include_once __DIR__ . '/../../../../tests/abstracts/AbstractDestinationFieldTest.php'; +include_once __DIR__ . '/../../../../tests/src/AbstractDestinationFieldTest.php'; final class TagDestinationFieldTest extends AbstractDestinationFieldTest { From 29aee01eebb383c919c76686f0b4535afaf59f53 Mon Sep 17 00:00:00 2001 From: MyuTsu Date: Wed, 2 Sep 2026 16:33:18 +0200 Subject: [PATCH 2/4] fix rector and tag field --- hook.php | 8 ++++---- inc/config.class.php | 6 +++--- inc/profile.class.php | 2 +- inc/tag.class.php | 8 +++----- inc/taginjection.class.php | 8 ++++---- inc/tagitem.class.php | 18 +++++++++--------- public/js/modules/TagDropdownColorizer.js | 5 ++--- tests/Units/TagDestinationFieldTest.php | 10 +++++++--- tests/Units/TagItemTest.php | 1 - 9 files changed, 33 insertions(+), 33 deletions(-) diff --git a/hook.php b/hook.php index 59c3f53f..93035c8f 100644 --- a/hook.php +++ b/hook.php @@ -350,10 +350,10 @@ function plugin_tag_post_init() // Always define hook for tickets // Needed for rules to function properly when a ticket is created from a mail // collector - $PLUGIN_HOOKS[Hooks::ITEM_ADD]['tag'][Ticket::getType()] = ['PluginTagTagItem', 'updateItem']; - $PLUGIN_HOOKS[Hooks::ITEM_UPDATE]['tag'][Ticket::getType()] = ['PluginTagTagItem', 'updateItem']; - $PLUGIN_HOOKS[Hooks::PRE_ITEM_UPDATE]['tag'][Ticket::getType()] = ['PluginTagTagItem', 'updateItem']; - $PLUGIN_HOOKS[Hooks::PRE_ITEM_PURGE]['tag'][Ticket::getType()] = ['PluginTagTagItem', 'purgeItem']; + $PLUGIN_HOOKS[Hooks::ITEM_ADD]['tag'][Ticket::class] = ['PluginTagTagItem', 'updateItem']; + $PLUGIN_HOOKS[Hooks::ITEM_UPDATE]['tag'][Ticket::class] = ['PluginTagTagItem', 'updateItem']; + $PLUGIN_HOOKS[Hooks::PRE_ITEM_UPDATE]['tag'][Ticket::class] = ['PluginTagTagItem', 'updateItem']; + $PLUGIN_HOOKS[Hooks::PRE_ITEM_PURGE]['tag'][Ticket::class] = ['PluginTagTagItem', 'purgeItem']; // Always define hook for Form (GLPI 11 namespace class) // Needed because getCurrentItemtype() doesn't handle namespaces correctly diff --git a/inc/config.class.php b/inc/config.class.php index 361f0030..f497e439 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -35,8 +35,8 @@ class PluginTagConfig extends CommonDBTM public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { - if (!$withtemplate && $item->getType() === 'Config') { - return self::createTabEntry(__('Tag Management', 'tag'), 0, $item::getType(), PluginTagTag::getIcon()); + if (!$withtemplate && $item::class === 'Config') { + return self::createTabEntry(__('Tag Management', 'tag'), 0, $item::class, PluginTagTag::getIcon()); } return ''; @@ -83,7 +83,7 @@ public function showConfigForm() public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { - if ($item->getType() == 'Config') { + if ($item::class == 'Config') { $config = new self(); $config->showConfigForm(); } diff --git a/inc/profile.class.php b/inc/profile.class.php index a33f22f9..3a8225cb 100644 --- a/inc/profile.class.php +++ b/inc/profile.class.php @@ -32,7 +32,7 @@ class PluginTagProfile extends Profile { public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { - return self::createTabEntry(__('Tag Management', 'tag'), 0, $item::getType(), PluginTagTag::getIcon()); + return self::createTabEntry(__('Tag Management', 'tag'), 0, $item::class, PluginTagTag::getIcon()); } public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) diff --git a/inc/tag.class.php b/inc/tag.class.php index 7518f916..06bc7395 100644 --- a/inc/tag.class.php +++ b/inc/tag.class.php @@ -256,7 +256,7 @@ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) ]); } - $tab[2] = self::createTabEntry(_sn('Associated item', 'Associated items', 2), $nb, $item::getType(), 'ti ti-list'); + $tab[2] = self::createTabEntry(_sn('Associated item', 'Associated items', 2), $nb, $item::class, 'ti ti-list'); return $tab; } @@ -556,9 +556,7 @@ public static function preKanbanContent($params = []) } if (isset($params['itemtype']) && isset($params['items_id'])) { - if (!isset($params['content'])) { - $params['content'] = ""; - } + $params['content'] ??= ""; $iterator = $DB->request([ 'SELECT' => [ @@ -913,7 +911,7 @@ public static function getCurrentItemtype() $item = getItemForItemtype($itemtype); if ($item instanceof CommonDBTM) { - return $item->getType(); + return $item::class; } return false; diff --git a/inc/taginjection.class.php b/inc/taginjection.class.php index b8097c79..7bdd6161 100644 --- a/inc/taginjection.class.php +++ b/inc/taginjection.class.php @@ -64,9 +64,9 @@ public function getOptions($primary_type = '') $options['displaytype'] = ["dropdown" => [12]]; return PluginDatainjectionCommonInjectionLib::addToSearchOptions($tab, $options, $this); - } else { - return []; } + + return []; } /** @@ -88,8 +88,8 @@ public function addOrUpdateObject($values = [], $options = []) } return $results; - } else { - return []; } + + return []; } } diff --git a/inc/tagitem.class.php b/inc/tagitem.class.php index 6ea954cb..dbb924a3 100644 --- a/inc/tagitem.class.php +++ b/inc/tagitem.class.php @@ -475,7 +475,7 @@ public static function updateItem(CommonDBTM $item, bool $delete_existing_tags = if ( $item->getID() && !isset($item->input["_plugin_tag_tag_process_form"]) - && ($item::getType() != Ticket::getType() || abs(strtotime((string) $item->fields['date_creation']) - strtotime((string) $_SESSION['glpi_currenttime'])) >= 5) + && ($item::class != Ticket::class || abs(strtotime((string) $item->fields['date_creation']) - strtotime((string) $_SESSION['glpi_currenttime'])) >= 5) ) { return true; } @@ -536,7 +536,7 @@ public static function updateItem(CommonDBTM $item, bool $delete_existing_tags = // process actions $existing_tags_ids = array_column( - $tag_item->find(['items_id' => $item->getID(), 'itemtype' => $item->getType()]), + $tag_item->find(['items_id' => $item->getID(), 'itemtype' => $item::class]), 'plugin_tag_tags_id', ); $added_tags_ids = array_diff($tag_values, $existing_tags_ids); @@ -550,7 +550,7 @@ public static function updateItem(CommonDBTM $item, bool $delete_existing_tags = $tag_item->add([ 'plugin_tag_tags_id' => $tag_id, 'items_id' => $item->getID(), - 'itemtype' => $item->getType(), + 'itemtype' => $item::class, ]); } @@ -558,7 +558,7 @@ public static function updateItem(CommonDBTM $item, bool $delete_existing_tags = $tag_item->deleteByCriteria([ 'plugin_tag_tags_id' => $tag_id, "items_id" => $item->getID(), - "itemtype" => $item->getType(), + "itemtype" => $item::class, ]); } @@ -591,7 +591,7 @@ public static function purgeItem(CommonDBTM $item) $tagitem = new self(); return $tagitem->deleteByCriteria([ "items_id" => $item->getID(), - "itemtype" => $item->getType(), + "itemtype" => $item::class, ]); } @@ -627,9 +627,9 @@ public static function processMassiveActionsForOneItemtype( $object->fields['id'] = $items_id; $object->input = $input; if (self::updateItem($object, false)) { - $ma->itemDone($item->getType(), $items_id, MassiveAction::ACTION_OK); + $ma->itemDone($item::class, $items_id, MassiveAction::ACTION_OK); } else { - $ma->itemDone($item->getType(), $items_id, MassiveAction::ACTION_KO); + $ma->itemDone($item::class, $items_id, MassiveAction::ACTION_KO); $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION)); } } @@ -648,9 +648,9 @@ public static function processMassiveActionsForOneItemtype( 'plugin_tag_tags_id' => $input['_plugin_tag_tag_values'], ]) ) { - $ma->itemDone($item->getType(), $items_id, MassiveAction::ACTION_OK); + $ma->itemDone($item::class, $items_id, MassiveAction::ACTION_OK); } else { - $ma->itemDone($item->getType(), $items_id, MassiveAction::ACTION_KO); + $ma->itemDone($item::class, $items_id, MassiveAction::ACTION_KO); $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION)); } } diff --git a/public/js/modules/TagDropdownColorizer.js b/public/js/modules/TagDropdownColorizer.js index cd134a63..6aa4b61f 100644 --- a/public/js/modules/TagDropdownColorizer.js +++ b/public/js/modules/TagDropdownColorizer.js @@ -63,8 +63,8 @@ export class GlpiPluginTagTagDropdownColorizer { /** * Get style for a given tag options. - * - * @param {object} options + * + * @param {object} options * @returns {object} */ tagStyle(options) { @@ -72,7 +72,6 @@ export class GlpiPluginTagTagDropdownColorizer { return { 'background-color': backgroundColor, 'color': this.isDark(backgroundColor) ? '#fff' : '', - 'padding': '2px 4px', 'border-radius': '2px', } } diff --git a/tests/Units/TagDestinationFieldTest.php b/tests/Units/TagDestinationFieldTest.php index 781ca25d..6b81788b 100644 --- a/tests/Units/TagDestinationFieldTest.php +++ b/tests/Units/TagDestinationFieldTest.php @@ -30,7 +30,9 @@ namespace GlpiPlugin\Tag\Tests\Units; +use CommonDBTM; use Glpi\Form\AnswersHandler\AnswersHandler; +use Glpi\Form\Destination\FormDestination; use Glpi\Form\Form; use Glpi\Tests\AbstractDestinationFieldTest; use Glpi\Tests\FormBuilder; @@ -209,8 +211,9 @@ private function sendFormAndAssertTicketTags( $destinations = $form->getDestinations(); $this->assertCount(1, $destinations); $destination = current($destinations); + $this->assertTrue($destination instanceof FormDestination); $this->updateItem( - $destination::getType(), + $destination::class, $destination->getId(), ['config' => [PluginTagDestinationField::getKey() => $config->jsonSerialize()]], ["config"], @@ -236,12 +239,13 @@ private function sendFormAndAssertTicketTags( $created_items = $answers->getCreatedItems(); $this->assertCount(1, $created_items); $ticket = current($created_items); + $this->assertTrue($ticket instanceof CommonDBTM); // Check ticket tags $tag_item = new PluginTagTagItem(); - $tags = $tag_item->find(['items_id' => $ticket->getId(), 'itemtype' => $ticket::getType()]); + $tags = $tag_item->find(['items_id' => $ticket->getId(), 'itemtype' => $ticket::class]); $this->assertCount(count($expected_tag_ids), $tags); - $tag_ids = array_map(fn($tag) => $tag['plugin_tag_tags_id'], $tags); + $tag_ids = array_values(array_map(fn($tag) => $tag['plugin_tag_tags_id'], $tags)); $this->assertEqualsCanonicalizing($expected_tag_ids, $tag_ids); } diff --git a/tests/Units/TagItemTest.php b/tests/Units/TagItemTest.php index 0a27e12f..f700cbe8 100644 --- a/tests/Units/TagItemTest.php +++ b/tests/Units/TagItemTest.php @@ -43,7 +43,6 @@ public function testTagsFromTicket(): void $tagID1 = $this->createTag('TicketTag1'); $tagID2 = $this->createTag('TicketTag2'); - $ticket = new Ticket(); $ticket->add([ 'name' => 'Ticket add Tag', From 93d8cec051c9ab7b1fd0a2b1f1cb2650d0dcc2f1 Mon Sep 17 00:00:00 2001 From: MyuTsu Date: Fri, 4 Sep 2026 15:04:30 +0200 Subject: [PATCH 3/4] plugin name --- setup.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.php b/setup.php index e68d5d50..4cd4e62a 100644 --- a/setup.php +++ b/setup.php @@ -182,7 +182,7 @@ function plugin_init_tag() function plugin_version_tag() { return [ - 'name' => __('Tag Management', 'tag'), + 'name' => 'Tag', 'version' => PLUGIN_TAG_VERSION, 'author' => 'Teclib\' - Infotel conseil', 'homepage' => 'https://github.com/pluginsGLPI/tag', From 4a07841df6ece97b5dfdf3041375833c2f6f09fa Mon Sep 17 00:00:00 2001 From: Stanislas Kita <7335054+stonebuzz@users.noreply.github.com> Date: Tue, 6 Oct 2026 12:50:02 +0200 Subject: [PATCH 4/4] bum version --- CHANGELOG.md | 2 +- plugin.xml | 5 +++++ setup.php | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86bdffe8..f963e5b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased] +## [2.15.0] - 2026-10-06 ### Added diff --git a/plugin.xml b/plugin.xml index 2ea68be8..4ab45e6a 100644 --- a/plugin.xml +++ b/plugin.xml @@ -33,6 +33,11 @@ TECLIB' + + 2.15.0 + ~12.0.0 + https://github.com/pluginsGLPI/tag/releases/download/2.15.0/glpi-tag-2.15.0.tar.bz2 + 2.14.8 ~11.0.1 diff --git a/setup.php b/setup.php index 4cd4e62a..bcacf36c 100644 --- a/setup.php +++ b/setup.php @@ -39,7 +39,7 @@ use function Safe\define; -define('PLUGIN_TAG_VERSION', '2.14.8'); +define('PLUGIN_TAG_VERSION', '2.15.0'); // Minimal GLPI version, inclusive define("PLUGIN_TAG_MIN_GLPI", "12.0.0");