Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Fix image (field : description) in to pdf
- Fix massive action PDF export redirecting to item list instead of generating the PDF
- Fix PDF export for assignable asset groups by properly handling multiple groups

## [4.1.2] - 2026-01-08

Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
},
"autoload-dev": {
"psr-4": {
"Glpi\\Tools\\": "../../tools/src/"
"Glpi\\Tools\\": "../../tools/src/",
"GlpiPlugin\\Pdf\\Tests\\": "tests/"
}
}
}
20 changes: 16 additions & 4 deletions inc/common.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ abstract class PluginPdfCommon extends CommonGLPI

public static $rightname = 'plugin_pdf';

protected static function getGroupName(CommonDBTM $item, int $group_type = Group_Item::GROUP_TYPE_NORMAL): string
{
$field = $group_type === Group_Item::GROUP_TYPE_TECH ? 'groups_id_tech' : 'groups_id';

// $item->fields[$field] is already an array of group ids for items using the
// AssignableItem trait (many-to-many relation via glpi_groups_items), and a scalar
// group id for items using a direct one-to-one column (e.g. glpi_itilcategories).
$group_ids = (array) ($item->fields[$field] ?? 0);

return implode(', ', array_filter(array_map(
static fn($group_id) => Toolbox::stripTags(Dropdown::getDropdownName('glpi_groups', $group_id)),
$group_ids,
)));
Comment on lines +49 to +52

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There’s something I’m not fully grasping in this PR.

In GLPI, an object can be assigned to a group using a one-to-one relationship (i.e., the object contains a groups_id or groups_id_tech column, for example in glpi_itilcategories).

Objects can also be assigned to multiple groups through an intermediate relation table, glpi_groups_items (cf: glpi_computers).

These objects rely on that relation table when they use the AssignableItem trait.

Here (unless I’m mistaken), we are only handling the first case.

}

/**
* Constructor, should intialize $this->obj property
**/
Expand Down Expand Up @@ -509,10 +524,7 @@ public static function mainLine(PluginPdfSimplePDF $pdf, $item, $field)
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('Group in charge of the hardware') . '</i></b>',
Dropdown::getDropdownName(
'glpi_groups',
$item->fields['groups_id_tech'],
),
self::getGroupName($item, Group_Item::GROUP_TYPE_TECH),
),
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
Expand Down
11 changes: 6 additions & 5 deletions inc/computer.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,13 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Computer $computer)
'<b><i>' . sprintf(
__('%1$s: %2$s'),
__('Group') . '</i></b>',
Dropdown::getDropdownName(
'glpi_groups',
$computer->fields['groups_id'],
),
self::getGroupName($computer),
),
'<b><i>' . sprintf(
__('%1$s: %2$s'),
__('UUID') . '</i></b>',
$computer->fields['uuid'],
),
'<b><i>' . sprintf(__('%1$s: %2$s'), __('UUID') . '</i></b>', $computer->fields['uuid']),
);

$pdf->displayLine(
Expand Down
6 changes: 1 addition & 5 deletions inc/monitor.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Monitor $item)
PluginPdfCommon::mainLine($pdf, $item, 'user-management');

$pdf->displayLine(
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('Group') . '</i></b>',
Dropdown::getDropdownName('glpi_groups', $item->fields['groups_id']),
),
'<b><i>' . sprintf(__s('%1$s: %2$s'), __s('Group') . '</i></b>', self::getGroupName($item)),
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('Size') . '</i></b>',
Expand Down
6 changes: 1 addition & 5 deletions inc/networkequipment.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, NetworkEquipment $item)
);

$pdf->displayLine(
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('Group') . '</i></b>',
Dropdown::getDropdownName('glpi_groups', $item->fields['groups_id']),
),
'<b><i>' . sprintf(__s('%1$s: %2$s'), __s('Group') . '</i></b>', self::getGroupName($item)),
'<b><i>' . __s('The MAC address and the IP of the equipment are included in an aggregated network port'),
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
Expand Down
6 changes: 1 addition & 5 deletions inc/peripheral.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Peripheral $item)
PluginPdfCommon::mainLine($pdf, $item, 'user-management');

$pdf->displayLine(
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('Group') . '</i></b>',
Dropdown::getDropdownName('glpi_groups', $item->fields['groups_id']),
),
'<b><i>' . sprintf(__s('%1$s: %2$s'), __s('Group') . '</i></b>', self::getGroupName($item)),
'<b><i>' . sprintf(__s('%1$s: %2$s'), __s('Brand') . '</i></b>', $item->fields['brand']),
);

Expand Down
12 changes: 2 additions & 10 deletions inc/phone.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,8 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Phone $item)


$pdf->displayLine(
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('Group') . '</i></b>',
Dropdown::getDropdownName('glpi_groups', $item->fields['groups_id']),
),
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('UUID') . '</i></b>',
$item->fields['uuid'],
),
'<b><i>' . sprintf(__s('%1$s: %2$s'), __s('Group') . '</i></b>', self::getGroupName($item)),
'<b><i>' . sprintf(__s('%1$s: %2$s'), __s('UUID') . '</i></b>', $item->fields['uuid']),
);

$pdf->displayLine(
Expand Down
12 changes: 2 additions & 10 deletions inc/printer.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,8 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Printer $printer)
);

$pdf->displayLine(
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('Group') . '</i></b>',
Dropdown::getDropdownName('glpi_groups', $printer->fields['groups_id']),
),
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('UUID') . '</i></b>',
$printer->fields['uuid'],
),
'<b><i>' . sprintf(__s('%1$s: %2$s'), __s('Group') . '</i></b>', self::getGroupName($printer)),
'<b><i>' . sprintf(__s('%1$s: %2$s'), __s('UUID') . '</i></b>', $printer->fields['uuid']),
);


Expand Down
7 changes: 2 additions & 5 deletions inc/software.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Software $software)
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('Group in charge of the hardware') . '</i></b>',
Dropdown::getDropdownName(
'glpi_groups',
$software->fields['groups_id_tech'],
),
self::getGroupName($software, Group_Item::GROUP_TYPE_TECH),
),
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
Expand All @@ -109,7 +106,7 @@ public static function pdfMain(PluginPdfSimplePDF $pdf, Software $software)
'<b><i>' . sprintf(
__s('%1$s: %2$s'),
__s('Group') . '</i></b>',
Dropdown::getDropdownName('glpi_groups', $software->fields['groups_id']),
self::getGroupName($software),
),
);

Expand Down
7 changes: 7 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<phpunit bootstrap="tests/bootstrap.php" colors="true" testdox="true">
<testsuites>
<testsuite name="Tests">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>
133 changes: 133 additions & 0 deletions tests/Units/GetGroupNameTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

/**
* -------------------------------------------------------------------------
* LICENSE
*
* This file is part of PDF plugin for GLPI.
*
* PDF is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PDF is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Reports. If not, see <http://www.gnu.org/licenses/>.
*
* @author Nelly Mahu-Lasson, Remi Collet, Teclib
* @copyright Copyright (c) 2009-2022 PDF plugin team
* @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 Computer;
use Glpi\Tests\DbTestCase;
use Group;
use Group_Item;
use ITILCategory;
use PluginPdfCommon;
use ReflectionMethod;

final class GetGroupNameTest extends DbTestCase
{
private function getGroupName(\CommonDBTM $item, int $group_type = Group_Item::GROUP_TYPE_NORMAL): string
{
$method = new ReflectionMethod(PluginPdfCommon::class, 'getGroupName');
$method->setAccessible(true);

return $method->invoke(null, $item, $group_type);
}

/**
* One-to-one relation: the group id is stored directly in the `groups_id` column
* (e.g. glpi_itilcategories), as a scalar value.
*/
public function testScalarGroupOnOneToOneRelation(): void
{
$group = $this->createItem(Group::class, [
'name' => 'One-to-one group',
'entities_id' => $this->getTestRootEntity(true),
]);

$category = $this->createItem(ITILCategory::class, [
'name' => 'Category with a group',
'entities_id' => $this->getTestRootEntity(true),
'groups_id' => $group->getID(),
]);
$category->getFromDB($category->getID());

$this->assertSame($group->fields['name'], $this->getGroupName($category));
}

public function testNoGroupOnOneToOneRelation(): void
{
$category = $this->createItem(ITILCategory::class, [
'name' => 'Category without a group',
'entities_id' => $this->getTestRootEntity(true),
]);
$category->getFromDB($category->getID());

$this->assertSame('', $this->getGroupName($category));
}

/**
* Many-to-many relation: groups are stored in the `glpi_groups_items` pivot table
* (AssignableItem trait, e.g. glpi_computers), as an array of ids.
*/
public function testArrayGroupsOnManyToManyRelation(): void
{
$group1 = $this->createItem(Group::class, [
'name' => 'Computer group 1',
'entities_id' => $this->getTestRootEntity(true),
]);
$group2 = $this->createItem(Group::class, [
'name' => 'Computer group 2',
'entities_id' => $this->getTestRootEntity(true),
]);
$tech_group = $this->createItem(Group::class, [
'name' => 'Computer tech group',
'entities_id' => $this->getTestRootEntity(true),
]);

$computer = $this->createItem(Computer::class, [
'name' => 'Computer with groups',
'entities_id' => $this->getTestRootEntity(true),
'groups_id' => [$group1->getID(), $group2->getID()],
'groups_id_tech' => [$tech_group->getID()],
]);
$computer->getFromDB($computer->getID());

$this->assertSame(
implode(', ', [$group1->fields['name'], $group2->fields['name']]),
$this->getGroupName($computer)
);
$this->assertSame(
$tech_group->fields['name'],
$this->getGroupName($computer, Group_Item::GROUP_TYPE_TECH)
);
}

public function testNoGroupsOnManyToManyRelation(): void
{
$computer = $this->createItem(Computer::class, [
'name' => 'Computer without groups',
'entities_id' => $this->getTestRootEntity(true),
]);
$computer->getFromDB($computer->getID());

$this->assertSame('', $this->getGroupName($computer));
$this->assertSame('', $this->getGroupName($computer, Group_Item::GROUP_TYPE_TECH));
}
}
37 changes: 37 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/**
* -------------------------------------------------------------------------
* LICENSE
*
* This file is part of PDF plugin for GLPI.
*
* PDF is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PDF is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Reports. If not, see <http://www.gnu.org/licenses/>.
*
* @author Nelly Mahu-Lasson, Remi Collet, Teclib
* @copyright Copyright (c) 2009-2022 PDF plugin team
* @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';

if (!Plugin::isPluginActive('pdf')) {
throw new RuntimeException('Plugin pdf is not active in the test database');
}
Loading