diff --git a/.gitignore b/.gitignore index 420fb40..29c20bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /vendor/ +.phpunit.result.cache var/ diff --git a/CHANGELOG.md b/CHANGELOG.md index e14fcbc..5a23807 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Dependencies conflicts with core - Internal server error when generating appliance asset pdf +- Display all groups and groups in charge in asset PDF exports +- Fix warning on the Domains tab of PDF exports - CI: fix Psalm cache directory, declare a unique composer autoloader suffix ## [4.1.5] - 2026-09-01 diff --git a/inc/appliance.class.php b/inc/appliance.class.php index 62852ef..7deff97 100644 --- a/inc/appliance.class.php +++ b/inc/appliance.class.php @@ -154,10 +154,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Appliance $item) sprintf( __s('%1$s: %2$s'), '' . __s('Group in charge of the hardware') . '', - Toolbox::stripTags(Dropdown::getDropdownName( - 'glpi_groups', - $item->fields['groups_id_tech'], - )), + PluginPdfCommon::getGroupNames($item->fields['groups_id_tech']), ), ); @@ -183,10 +180,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Appliance $item) sprintf( __s('%1$s: %2$s'), '' . __s('Group') . '', - Toolbox::stripTags(Dropdown::getDropdownName( - 'glpi_groups', - $item->fields['groups_id'], - )), + PluginPdfCommon::getGroupNames($item->fields['groups_id']), ), ); diff --git a/inc/cartridgeitem.class.php b/inc/cartridgeitem.class.php index 63a09db..47cad78 100644 --- a/inc/cartridgeitem.class.php +++ b/inc/cartridgeitem.class.php @@ -95,10 +95,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, CartridgeItem $cartitem) '' . sprintf( __s('%1$s: %2$s'), __s('Group in charge of the hardware') . '', - Dropdown::getDropdownName( - 'glpi_groups', - $cartitem->fields['groups_id_tech'], - ), + PluginPdfCommon::getGroupNames($cartitem->fields['groups_id_tech']), ), ); diff --git a/inc/common.class.php b/inc/common.class.php index 49509e9..e7f5fa9 100644 --- a/inc/common.class.php +++ b/inc/common.class.php @@ -431,6 +431,21 @@ final public function generatePDF($tab_id, $tabs, $page = 0, $render = true) } } + /** + * Get the names of groups, sorted and separated by commas, ready to be displayed in a PDF cell + * + * @param array $groups_ids + * + * @return string + */ + public static function getGroupNames(array $groups_ids): string + { + $names = Dropdown::getDropdownArrayNames('glpi_groups', $groups_ids); + natcasesort($names); + + return Toolbox::stripTags(implode(', ', $names)); + } + public static function mainTitle(PluginPdfSimplePDF $pdf, $item) { $pdf->setColumnsSize(50, 50); @@ -520,10 +535,7 @@ public static function mainLine(PluginPdfSimplePDF $pdf, $item, $field) '' . sprintf( __s('%1$s: %2$s'), __s('Group in charge of the hardware') . '', - Dropdown::getDropdownName( - 'glpi_groups', - $item->fields['groups_id_tech'], - ), + self::getGroupNames($item->fields['groups_id_tech']), ), '' . sprintf( __s('%1$s: %2$s'), diff --git a/inc/computer.class.php b/inc/computer.class.php index 0b610cf..79c46d2 100644 --- a/inc/computer.class.php +++ b/inc/computer.class.php @@ -91,10 +91,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Computer $computer) '' . sprintf( __('%1$s: %2$s'), __('Group') . '', - Dropdown::getDropdownName( - 'glpi_groups', - $computer->fields['groups_id'], - ), + PluginPdfCommon::getGroupNames($computer->fields['groups_id']), ), '' . sprintf(__('%1$s: %2$s'), __('UUID') . '', $computer->fields['uuid']), ); diff --git a/inc/consumableitem.class.php b/inc/consumableitem.class.php index 991a641..7745472 100644 --- a/inc/consumableitem.class.php +++ b/inc/consumableitem.class.php @@ -84,10 +84,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, ConsumableItem $consitem '' . sprintf( __s('%1$s: %2$s'), __s('Group in charge of the hardware') . '', - Dropdown::getDropdownName( - 'glpi_groups', - $consitem->fields['groups_id_tech'], - ), + PluginPdfCommon::getGroupNames($consitem->fields['groups_id_tech']), ), ); diff --git a/inc/domain_item.class.php b/inc/domain_item.class.php index 22e5456..448df89 100644 --- a/inc/domain_item.class.php +++ b/inc/domain_item.class.php @@ -84,11 +84,35 @@ public static function pdfForItem(PluginPdfSimplePDF $pdf, CommonDBTM $item) __s('Expiration date'), ); - foreach ($result as $data) { + $domains = iterator_to_array($result, false); + $tech_groups = []; + $groups = $DB->request([ + 'SELECT' => ['glpi_groups_items.items_id', 'glpi_groups.completename'], + 'FROM' => Group_Item::getTable(), + 'INNER JOIN' => [ + 'glpi_groups' => [ + 'FKEY' => [ + 'glpi_groups_items' => 'groups_id', + 'glpi_groups' => 'id', + ], + ], + ], + 'WHERE' => [ + 'glpi_groups_items.itemtype' => Domain::class, + 'glpi_groups_items.items_id' => array_column($domains, 'id'), + 'glpi_groups_items.type' => Group_Item::GROUP_TYPE_TECH, + ], + 'ORDER' => 'glpi_groups.completename', + ]); + foreach ($groups as $group) { + $tech_groups[$group['items_id']][] = $group['completename']; + } + + foreach ($domains as $data) { $pdf->displayLine( $data['name'], Dropdown::getDropdownName('glpi_entities', $data['entities_id']), - Dropdown::getDropdownName('glpi_groups', $data['groups_id_tech']), + Toolbox::stripTags(implode(', ', $tech_groups[$data['id']] ?? [])), getUserName($data['users_id_tech']), Dropdown::getDropdownName('glpi_domaintypes', $data['domaintypes_id']), Dropdown::getDropdownName('glpi_domainrelations', $data['domainrelations_id']), diff --git a/inc/monitor.class.php b/inc/monitor.class.php index 5d7ccc7..52ffbb4 100644 --- a/inc/monitor.class.php +++ b/inc/monitor.class.php @@ -64,7 +64,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Monitor $item) '' . sprintf( __s('%1$s: %2$s'), __s('Group') . '', - Dropdown::getDropdownName('glpi_groups', $item->fields['groups_id']), + PluginPdfCommon::getGroupNames($item->fields['groups_id']), ), '' . sprintf( __s('%1$s: %2$s'), diff --git a/inc/networkequipment.class.php b/inc/networkequipment.class.php index cbd1155..9c68429 100644 --- a/inc/networkequipment.class.php +++ b/inc/networkequipment.class.php @@ -86,7 +86,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, NetworkEquipment $item) '' . sprintf( __s('%1$s: %2$s'), __s('Group') . '', - Dropdown::getDropdownName('glpi_groups', $item->fields['groups_id']), + PluginPdfCommon::getGroupNames($item->fields['groups_id']), ), '' . __s('The MAC address and the IP of the equipment are included in an aggregated network port'), '' . sprintf( diff --git a/inc/peripheral.class.php b/inc/peripheral.class.php index 9f38312..6b712d9 100644 --- a/inc/peripheral.class.php +++ b/inc/peripheral.class.php @@ -66,7 +66,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Peripheral $item) '' . sprintf( __s('%1$s: %2$s'), __s('Group') . '', - Dropdown::getDropdownName('glpi_groups', $item->fields['groups_id']), + PluginPdfCommon::getGroupNames($item->fields['groups_id']), ), '' . sprintf(__s('%1$s: %2$s'), __s('Brand') . '', $item->fields['brand']), ); diff --git a/inc/phone.class.php b/inc/phone.class.php index e35cf92..7fbfa9c 100644 --- a/inc/phone.class.php +++ b/inc/phone.class.php @@ -67,7 +67,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Phone $item) '' . sprintf( __s('%1$s: %2$s'), __s('Group') . '', - Dropdown::getDropdownName('glpi_groups', $item->fields['groups_id']), + PluginPdfCommon::getGroupNames($item->fields['groups_id']), ), '' . sprintf( __s('%1$s: %2$s'), diff --git a/inc/printer.class.php b/inc/printer.class.php index d493fc0..e695603 100644 --- a/inc/printer.class.php +++ b/inc/printer.class.php @@ -99,7 +99,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Printer $printer) '' . sprintf( __s('%1$s: %2$s'), __s('Group') . '', - Dropdown::getDropdownName('glpi_groups', $printer->fields['groups_id']), + PluginPdfCommon::getGroupNames($printer->fields['groups_id']), ), '' . sprintf( __s('%1$s: %2$s'), diff --git a/inc/software.class.php b/inc/software.class.php index 21a3526..756fc69 100644 --- a/inc/software.class.php +++ b/inc/software.class.php @@ -93,10 +93,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Software $software) '' . sprintf( __s('%1$s: %2$s'), __s('Group in charge of the hardware') . '', - Dropdown::getDropdownName( - 'glpi_groups', - $software->fields['groups_id_tech'], - ), + PluginPdfCommon::getGroupNames($software->fields['groups_id_tech']), ), '' . sprintf( __s('%1$s: %2$s'), @@ -109,7 +106,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Software $software) '' . sprintf( __s('%1$s: %2$s'), __s('Group') . '', - Dropdown::getDropdownName('glpi_groups', $software->fields['groups_id']), + PluginPdfCommon::getGroupNames($software->fields['groups_id']), ), ); diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..e66703d --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,11 @@ + + + + tests/units + + + diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..5783003 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,50 @@ +. + * + * @author Nelly Mahu-Lasson, Remi Collet, Teclib + * @copyright Copyright (c) 2009-2022 PDF plugin team + * @copyright 2015-2024 Teclib' and contributors. + * @copyright 2003-2014 by the INDEPNET Development Team. + * @licence https://www.gnu.org/licenses/gpl-3.0.html + * @license AGPL License 3.0 or (at your option) any later version + * @link https://github.com/pluginsGLPI/pdf/ + * @link http://www.glpi-project.org/ + * @package pdf + * @since 2009 + * http://www.gnu.org/licenses/agpl-3.0-standalone.html + * -------------------------------------------------------------------------- + */ + +require __DIR__ . '/../../../tests/bootstrap.php'; + +$plugin = new Plugin(); +$plugin->checkPluginState('pdf'); +$plugin->getFromDBbyDir('pdf'); + +if (!$plugin->isInstalled('pdf')) { + $plugin->install($plugin->getID()); +} + +if (!$plugin->isActivated('pdf')) { + $plugin->activate($plugin->getID()); +} + +require_once __DIR__ . '/fixtures/RecordingSimplePDF.php'; diff --git a/tests/fixtures/RecordingSimplePDF.php b/tests/fixtures/RecordingSimplePDF.php new file mode 100644 index 0000000..54df30d --- /dev/null +++ b/tests/fixtures/RecordingSimplePDF.php @@ -0,0 +1,62 @@ +. + * + * @author Nelly Mahu-Lasson, Remi Collet, Teclib + * @copyright Copyright (c) 2009-2022 PDF plugin team + * @copyright 2015-2024 Teclib' and contributors. + * @copyright 2003-2014 by the INDEPNET Development Team. + * @licence https://www.gnu.org/licenses/gpl-3.0.html + * @license AGPL License 3.0 or (at your option) any later version + * @link https://github.com/pluginsGLPI/pdf/ + * @link http://www.glpi-project.org/ + * @package pdf + * @since 2009 + * http://www.gnu.org/licenses/agpl-3.0-standalone.html + * -------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Pdf\Tests; + +use PluginPdfSimplePDF; + +class RecordingSimplePDF extends PluginPdfSimplePDF +{ + /** @var string[] */ + public array $cells = []; + + public function __construct() + { + parent::__construct(); + $this->newPage(); + } + + public function displayTitle() + { + array_push($this->cells, ...func_get_args()); + parent::displayTitle(...func_get_args()); + } + + public function displayLine() + { + array_push($this->cells, ...func_get_args()); + parent::displayLine(...func_get_args()); + } +} diff --git a/tests/units/GroupsDisplayTest.php b/tests/units/GroupsDisplayTest.php new file mode 100644 index 0000000..36190a4 --- /dev/null +++ b/tests/units/GroupsDisplayTest.php @@ -0,0 +1,168 @@ +. + * + * @author Nelly Mahu-Lasson, Remi Collet, Teclib + * @copyright Copyright (c) 2009-2022 PDF plugin team + * @copyright 2015-2024 Teclib' and contributors. + * @copyright 2003-2014 by the INDEPNET Development Team. + * @licence https://www.gnu.org/licenses/gpl-3.0.html + * @license AGPL License 3.0 or (at your option) any later version + * @link https://github.com/pluginsGLPI/pdf/ + * @link http://www.glpi-project.org/ + * @package pdf + * @since 2009 + * http://www.gnu.org/licenses/agpl-3.0-standalone.html + * -------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Pdf\Tests\Units; + +use Appliance; +use CartridgeItem; +use Computer; +use ConsumableItem; +use Domain; +use Domain_Item; +use Glpi\Tests\DbTestCase; +use GlpiPlugin\Pdf\Tests\RecordingSimplePDF; +use Group; +use Monitor; +use NetworkEquipment; +use Peripheral; +use Phone; +use PHPUnit\Framework\Attributes\DataProvider; +use PluginPdfAppliance; +use PluginPdfCartridgeItem; +use PluginPdfComputer; +use PluginPdfConsumableItem; +use PluginPdfDomain_Item; +use PluginPdfMonitor; +use PluginPdfNetworkEquipment; +use PluginPdfPeripheral; +use PluginPdfPhone; +use PluginPdfPrinter; +use PluginPdfSoftware; +use Printer; +use Software; + +class GroupsDisplayTest extends DbTestCase +{ + private const GROUP_CELL = 'Group: %s'; + private const TECH_GROUP_CELL = 'Group in charge of the hardware: %s'; + + public static function pdfMainProvider(): iterable + { + $assets = [ + 'Computer' => [Computer::class, PluginPdfComputer::class], + 'Monitor' => [Monitor::class, PluginPdfMonitor::class], + 'NetworkEquipment' => [NetworkEquipment::class, PluginPdfNetworkEquipment::class], + 'Peripheral' => [Peripheral::class, PluginPdfPeripheral::class], + 'Phone' => [Phone::class, PluginPdfPhone::class], + 'Printer' => [Printer::class, PluginPdfPrinter::class], + 'Software' => [Software::class, PluginPdfSoftware::class], + 'Appliance' => [Appliance::class, PluginPdfAppliance::class], + ]; + foreach ($assets as $label => [$itemtype, $pdf_class]) { + yield "$label groups" => [ + 'itemtype' => $itemtype, + 'pdf_class' => $pdf_class, + 'field' => 'groups_id', + 'template' => self::GROUP_CELL, + ]; + yield "$label tech groups" => [ + 'itemtype' => $itemtype, + 'pdf_class' => $pdf_class, + 'field' => 'groups_id_tech', + 'template' => self::TECH_GROUP_CELL, + ]; + } + yield 'CartridgeItem tech groups' => [ + 'itemtype' => CartridgeItem::class, + 'pdf_class' => PluginPdfCartridgeItem::class, + 'field' => 'groups_id_tech', + 'template' => self::TECH_GROUP_CELL, + ]; + yield 'ConsumableItem tech groups' => [ + 'itemtype' => ConsumableItem::class, + 'pdf_class' => PluginPdfConsumableItem::class, + 'field' => 'groups_id_tech', + 'template' => self::TECH_GROUP_CELL, + ]; + } + + #[DataProvider('pdfMainProvider')] + public function testPdfMainDisplaysAllGroups(string $itemtype, string $pdf_class, string $field, string $template): void + { + $this->login(); + $group_b = $this->createItem(Group::class, ['name' => 'PDF group B', 'entities_id' => 0]); + $group_a = $this->createItem(Group::class, ['name' => 'PDF group A', 'entities_id' => 0]); + + $item = $this->createItem($itemtype, [ + 'name' => 'PDF item', + 'entities_id' => 0, + $field => [$group_a->getID(), $group_b->getID()], + ]); + + $pdf = new RecordingSimplePDF(); + $pdf_class::pdfMain($pdf, $item); + + $this->assertContains(sprintf($template, 'PDF group A, PDF group B'), $pdf->cells); + } + + #[DataProvider('pdfMainProvider')] + public function testPdfMainDisplaysNoGroup(string $itemtype, string $pdf_class, string $field, string $template): void + { + $this->login(); + $item = $this->createItem($itemtype, [ + 'name' => 'PDF item', + 'entities_id' => 0, + ]); + + $pdf = new RecordingSimplePDF(); + $pdf_class::pdfMain($pdf, $item); + + $this->assertContains(sprintf($template, ''), $pdf->cells); + } + + public function testDomainItemDisplaysAllTechGroups(): void + { + $this->login(); + $group_b = $this->createItem(Group::class, ['name' => 'PDF group B', 'entities_id' => 0]); + $group_a = $this->createItem(Group::class, ['name' => 'PDF group A', 'entities_id' => 0]); + + $computer = $this->createItem(Computer::class, ['name' => 'PDF computer', 'entities_id' => 0]); + $domain = $this->createItem(Domain::class, [ + 'name' => 'pdf.example.com', + 'entities_id' => 0, + 'groups_id_tech' => [$group_a->getID(), $group_b->getID()], + ]); + $this->createItem(Domain_Item::class, [ + 'domains_id' => $domain->getID(), + 'itemtype' => Computer::class, + 'items_id' => $computer->getID(), + ]); + + $pdf = new RecordingSimplePDF(); + PluginPdfDomain_Item::pdfForItem($pdf, $computer); + + $this->assertContains('PDF group A, PDF group B', $pdf->cells); + } +}