Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to implement a specific logic when a capacity is enabled #18454

Merged
merged 1 commit into from
Dec 4, 2024
Merged
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
48 changes: 0 additions & 48 deletions .phpstan-baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -2473,12 +2473,6 @@
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Asset/Asset.php',
];
$ignoreErrors[] = [
'message' => '#^Instanceof between Glpi\\\\Asset\\\\AssetDefinition and Glpi\\\\Asset\\\\AssetDefinition will always evaluate to true\\.$#',
'identifier' => 'instanceof.alwaysTrue',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Asset/Asset.php',
];
$ignoreErrors[] = [
'message' => '#^Method Glpi\\\\Asset\\\\Asset\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\Asset\\)\\|false but returns object\\.$#',
'identifier' => 'return.type',
Expand All @@ -2503,24 +2497,12 @@
'count' => 2,
'path' => __DIR__ . '/src/Glpi/Asset/AssetDefinitionManager.php',
];
$ignoreErrors[] = [
'message' => '#^Instanceof between Glpi\\\\Asset\\\\AssetDefinition and Glpi\\\\Asset\\\\AssetDefinition will always evaluate to true\\.$#',
'identifier' => 'instanceof.alwaysTrue',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Asset/AssetModel.php',
];
$ignoreErrors[] = [
'message' => '#^Method Glpi\\\\Asset\\\\AssetModel\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\AssetModel\\)\\|false but returns Glpi\\\\Asset\\\\AssetModel\\.$#',
'identifier' => 'return.type',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Asset/AssetModel.php',
];
$ignoreErrors[] = [
'message' => '#^Instanceof between Glpi\\\\Asset\\\\AssetDefinition and Glpi\\\\Asset\\\\AssetDefinition will always evaluate to true\\.$#',
'identifier' => 'instanceof.alwaysTrue',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Asset/AssetType.php',
];
$ignoreErrors[] = [
'message' => '#^Method Glpi\\\\Asset\\\\AssetType\\:\\:getById\\(\\) should return static\\(Glpi\\\\Asset\\\\AssetType\\)\\|false but returns Glpi\\\\Asset\\\\AssetType\\.$#',
'identifier' => 'return.type',
Expand All @@ -2545,30 +2527,6 @@
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Asset/Capacity/CapacityInterface.php',
];
$ignoreErrors[] = [
'message' => '#^Instanceof between Glpi\\\\Asset\\\\AssetDefinition and Glpi\\\\Asset\\\\AssetDefinition will always evaluate to true\\.$#',
'identifier' => 'instanceof.alwaysTrue',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Asset/RuleDictionaryModel.php',
];
$ignoreErrors[] = [
'message' => '#^Instanceof between Glpi\\\\Asset\\\\AssetDefinition and Glpi\\\\Asset\\\\AssetDefinition will always evaluate to true\\.$#',
'identifier' => 'instanceof.alwaysTrue',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Asset/RuleDictionaryModelCollection.php',
];
$ignoreErrors[] = [
'message' => '#^Instanceof between Glpi\\\\Asset\\\\AssetDefinition and Glpi\\\\Asset\\\\AssetDefinition will always evaluate to true\\.$#',
'identifier' => 'instanceof.alwaysTrue',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Asset/RuleDictionaryType.php',
];
$ignoreErrors[] = [
'message' => '#^Instanceof between Glpi\\\\Asset\\\\AssetDefinition and Glpi\\\\Asset\\\\AssetDefinition will always evaluate to true\\.$#',
'identifier' => 'instanceof.alwaysTrue',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Asset/RuleDictionaryTypeCollection.php',
];
$ignoreErrors[] = [
'message' => '#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#',
'identifier' => 'function.alreadyNarrowedType',
Expand Down Expand Up @@ -2953,12 +2911,6 @@
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Debug/ProfilerSection.php',
];
$ignoreErrors[] = [
'message' => '#^Instanceof between Glpi\\\\Dropdown\\\\DropdownDefinition and Glpi\\\\Dropdown\\\\DropdownDefinition will always evaluate to true\\.$#',
'identifier' => 'instanceof.alwaysTrue',
'count' => 1,
'path' => __DIR__ . '/src/Glpi/Dropdown/Dropdown.php',
];
$ignoreErrors[] = [
'message' => '#^Method Glpi\\\\Dropdown\\\\Dropdown\\:\\:getById\\(\\) should return static\\(Glpi\\\\Dropdown\\\\Dropdown\\)\\|false but returns object\\.$#',
'identifier' => 'return.type',
Expand Down
30 changes: 0 additions & 30 deletions phpunit/DbTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -397,20 +397,6 @@ protected function initAssetDefinition(
$this->callPrivateMethod($definition, 'getDecodedProfilesField')
);

// Clear definition cache
$rc = new ReflectionClass(\Glpi\CustomObject\AbstractDefinitionManager::class);
$rc->getProperty('definitions_data')->setValue(\Glpi\Asset\AssetDefinitionManager::getInstance(), []);

$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);

return $definition;
}

Expand Down Expand Up @@ -472,14 +458,6 @@ protected function enableCapacity(
$this->callPrivateMethod($definition, 'getDecodedCapacitiesField')
);

// Force boostrap to trigger methods such as "onClassBootstrap"
$manager = AssetDefinitionManager::getInstance();
$this->callPrivateMethod(
$manager,
'boostrapConcreteClass',
$definition
);

return $definition;
}

Expand Down Expand Up @@ -520,14 +498,6 @@ protected function disableCapacity(
$this->callPrivateMethod($definition, 'getDecodedCapacitiesField')
);

// Force boostrap to trigger methods such as "onClassBootstrap"
$manager = AssetDefinitionManager::getInstance();
$this->callPrivateMethod(
$manager,
'boostrapConcreteClass',
$definition
);

return $definition;
}
}
4 changes: 4 additions & 0 deletions phpunit/GLPITestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
*/

use Glpi\Asset\AssetDefinitionManager;
use Glpi\Dropdown\DropdownDefinitionManager;
use Glpi\Tests\Log\TestHandler;
use Monolog\Level;
use Monolog\Logger;
Expand Down Expand Up @@ -87,6 +88,9 @@ public function setUp(): void
$SQLLOGGER->setHandlers([$this->sql_log_handler]);

vfsStreamWrapper::register();

AssetDefinitionManager::getInstance()->registerAutoload();
DropdownDefinitionManager::getInstance()->registerAutoload();
}

public function tearDown(): void
Expand Down
9 changes: 5 additions & 4 deletions src/Glpi/Asset/Asset.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ abstract class Asset extends CommonDBTM
use \Glpi\Features\Inventoriable;

/**
* Asset definition.
* Asset definition system name.
*
* 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;
protected static string $definition_system_name;

final public function __construct()
{
Expand All @@ -84,11 +84,12 @@ final public function __construct()
*/
public static function getDefinition(): AssetDefinition
{
if (!(static::$definition instanceof AssetDefinition)) {
$definition = AssetDefinitionManager::getInstance()->getDefinition(static::$definition_system_name);
if (!($definition instanceof AssetDefinition)) {
throw new \RuntimeException('Asset definition is expected to be defined in concrete class.');
}

return static::$definition;
return $definition;
}

public static function getDefinitionClass(): string
Expand Down
74 changes: 56 additions & 18 deletions src/Glpi/Asset/AssetDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
Expand Down Expand Up @@ -306,6 +305,14 @@ protected function prepareInput(array $input): array|bool

public function post_addItem()
{
parent::post_addItem();

// Trigger the `onCapacityEnabled` hooks.
$added_capacities = @json_decode($this->fields['capacities']);
foreach ($added_capacities as $capacity_classname) {
$this->onCapacityEnabled($capacity_classname);
}

// Add default display preferences for the new asset definition
$prefs = [
4, // Name
Expand All @@ -324,14 +331,13 @@ public function post_addItem()
'users_id' => 0,
]);
}

parent::post_addItem();
}

public function post_updateItem($history = true)
{
parent::post_updateItem();

if (in_array('capacities', $this->updates)) {
// When capabilities are removed, trigger the cleaning of data related to this capacity.
$new_capacities = @json_decode($this->fields['capacities']);
$old_capacities = @json_decode($this->oldvalues['capacities']);

Expand All @@ -352,28 +358,25 @@ public function post_updateItem($history = true)
return;
}

$removed_capacities = array_diff($old_capacities, $new_capacities);
$rights_to_remove = [];
foreach ($removed_capacities as $capacity_classname) {
$capacity = AssetDefinitionManager::getInstance()->getCapacity($capacity_classname);
if ($capacity === null) {
// can be null if provided by a plugin that is no longer active
continue;
}
$capacity->onCapacityDisabled($this->getAssetClassName());
array_push($rights_to_remove, ...$capacity->getSpecificRights());
$added_capacities = array_diff($new_capacities, $old_capacities);
foreach ($added_capacities as $capacity_classname) {
$this->onCapacityEnabled($capacity_classname);
}

if (count($rights_to_remove) > 0) {
$this->cleanRights($rights_to_remove);
$removed_capacities = array_diff($old_capacities, $new_capacities);
foreach ($removed_capacities as $capacity_classname) {
$this->onCapacityDisabled($capacity_classname);
}
}

parent::post_updateItem();
}

public function cleanDBonPurge()
{
$capacities = $this->getDecodedCapacitiesField();
foreach ($capacities as $capacity_classname) {
$this->onCapacityDisabled($capacity_classname);
}

$related_classes = [
$this->getAssetClassName(),
$this->getAssetModelClassName(),
Expand All @@ -389,6 +392,41 @@ public function cleanDBonPurge()
}
}

/**
* Handle the activation of a capacity.
*
* @phpstan-param class-string<\Glpi\Asset\Capacity\CapacityInterface> $capacity_classname
*/
private function onCapacityEnabled(string $capacity_classname): void
{
$capacity = AssetDefinitionManager::getInstance()->getCapacity($capacity_classname);
if ($capacity === null) {
// can be null if provided by a plugin that is no longer active
return;
}
$capacity->onCapacityEnabled($this->getAssetClassName());
}

/**
* Handle the deactivation of a capacity.
*
* @phpstan-param class-string<\Glpi\Asset\Capacity\CapacityInterface> $capacity_classname
*/
private function onCapacityDisabled(string $capacity_classname): void
{
$capacity = AssetDefinitionManager::getInstance()->getCapacity($capacity_classname);
if ($capacity === null) {
// can be null if provided by a plugin that is no longer active
return;
}
$capacity->onCapacityDisabled($this->getAssetClassName());

$rights_to_remove = $capacity->getSpecificRights();
if (count($rights_to_remove) > 0) {
$this->cleanRights($rights_to_remove);
}
}

public function rawSearchOptions()
{
$search_options = parent::rawSearchOptions();
Expand Down
Loading
Loading