From 7cd5e2591311926a4ea77a08bc599d1d10da30bf Mon Sep 17 00:00:00 2001 From: Thetsmr Date: Thu, 7 May 2026 14:52:45 +0200 Subject: [PATCH 1/2] Permit to Inject GlpiAsset --- inc/commoninjectionlib.class.php | 16 +++++ inc/injectiontype.class.php | 6 +- setup.php | 109 ++++++++++++++++++++++++++++++- 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/inc/commoninjectionlib.class.php b/inc/commoninjectionlib.class.php index 1ee5679c..acbb40ec 100644 --- a/inc/commoninjectionlib.class.php +++ b/inc/commoninjectionlib.class.php @@ -27,6 +27,7 @@ * @link https://github.com/pluginsGLPI/datainjection * ------------------------------------------------------------------------- */ +use Glpi\Asset\Asset; use Glpi\Exception\Http\HttpException; use Glpi\Features\AssignableItem; @@ -334,6 +335,9 @@ public static function getItemtypeByInjection($injectionClassName) public static function getItemtypeByInjectionClass($injectionClass) { + if (is_a($injectionClass, Asset::class, true)) { + return Toolbox::ucfirst(getItemTypeForTable($injectionClass->getVirtualTable())); + } return Toolbox::ucfirst(getItemTypeForTable($injectionClass->getTable())); } @@ -355,6 +359,11 @@ public static function getInjectionClassInstance($itemtype) $injectionClass = ucfirst($itemtype) . 'Injection'; } + if (!class_exists($injectionClass)) { + plugin_datainjection_creationInjectableAssets(); + } + + if (!is_a($injectionClass, PluginDatainjectionInjectionInterface::class, true)) { throw new HttpException(500, 'Class ' . $injectionClass . ' is not a valid class'); } @@ -1994,6 +2003,13 @@ private function dataAlreadyInDB($injectionClass, $itemtype) } } + if (is_a($injectionClass, Asset::class, true)) { + if (method_exists($injectionClass, 'getAssetDefinitionID')) { + $assets_assetdefinitions_id = $injectionClass->getAssetDefinitionID(); + $where .= " AND `assets_assetdefinitions_id` = '" . $assets_assetdefinitions_id . "'"; + } + } + //Add additional parameters specific to this itemtype (or function checkPresent exists) if (method_exists($injectionClass, 'checkPresent')) { $where .= $injectionClass->checkPresent($this->values, $options); diff --git a/inc/injectiontype.class.php b/inc/injectiontype.class.php index 9cfb291d..d74aa3cf 100644 --- a/inc/injectiontype.class.php +++ b/inc/injectiontype.class.php @@ -78,6 +78,10 @@ public static function getItemtypes($only_primary = false) $name = $plugin->getName() . ': '; } $name .= call_user_func([$type, 'getTypeName']); + + if ($typename == "GlpiPlugin\Datainjection\Glpi\Asset\AssetInjection") { + $typename = $instance->getVirtualType(); + } $values[$typename] = $name; } } @@ -388,7 +392,7 @@ public static function getUsedMappingsOrInfos($options = []) foreach ($options as $option) { if ( isset($option['table']) - && ($option['table'] == getItemTypeForTable($data['itemtype'])) + && ($option['table'] == $injectionClass->getTable()) && ($option['linkfield'] == $data['value']) && ($option['displaytype'] != 'multiline_text') && ($mapping_or_info['value'] != $data['value']) diff --git a/setup.php b/setup.php index 0fbbabe3..c7f834e4 100644 --- a/setup.php +++ b/setup.php @@ -28,6 +28,10 @@ * ------------------------------------------------------------------------- */ +use Glpi\Asset\AssetDefinition; +use Glpi\Asset\AssetDefinitionManager; +use GlpiPlugin\Datainjection\Glpi\Asset\Capacity\IsInjectableCapacity; + use function Safe\define; use function Safe\mkdir; @@ -49,6 +53,12 @@ function plugin_init_datainjection() /** @var array $INJECTABLE_TYPES */ global $PLUGIN_HOOKS, $CFG_GLPI, $INJECTABLE_TYPES; + if (!isset($CFG_GLPI['injectable_types'])) { + $CFG_GLPI['injectable_types'] = []; + } + $asset_definition_manager = AssetDefinitionManager::getInstance(); + $asset_definition_manager->registerCapacity(new IsInjectableCapacity()); + $PLUGIN_HOOKS['csrf_compliant']['datainjection'] = true; $PLUGIN_HOOKS['migratetypes']['datainjection'] = 'plugin_datainjection_migratetypes_datainjection'; @@ -84,6 +94,8 @@ function plugin_init_datainjection() $PLUGIN_HOOKS['add_javascript']['datainjection'] = 'js/datainjection.js'; $INJECTABLE_TYPES = []; + +// plugin_datainjection_creationInjectableAssets(); } } @@ -116,7 +128,7 @@ function getTypesToInject(): void { /** @var array $INJECTABLE_TYPES */ /** @var array $PLUGIN_HOOKS */ - global $INJECTABLE_TYPES,$PLUGIN_HOOKS; + global $INJECTABLE_TYPES,$CFG_GLPI; if (count($INJECTABLE_TYPES)) { // already populated @@ -220,6 +232,101 @@ function getTypesToInject(): void ]; //Add plugins Plugin::doHook('plugin_datainjection_populate'); + + // Register injectable assets dynamically + plugin_datainjection_registerInjectableAssets(); + + plugin_datainjection_creationInjectableAssets(); +} + + +/** + * Register injection classes for each injectable asset definition + */ +function plugin_datainjection_registerInjectableAssets(): void +{ + /** @var array $INJECTABLE_TYPES */ + /** @var array $CFG_GLPI */ + global $INJECTABLE_TYPES, $CFG_GLPI; + + if (!isset($CFG_GLPI['injectable_types']) || empty($CFG_GLPI['injectable_types'])) { + return; + } + + // For each injectable asset definition, create and register a distinct class + foreach ($CFG_GLPI['injectable_types'] as $definition_id => $itemtype) { + // Get the asset definition to extract the system name + + $definition = AssetDefinition::getById($definition_id); + if ($definition->getAssetClassName() === $itemtype) { + // Use the system name to create a nice class name + $system_name = ucfirst($definition->fields['system_name']);//strtolower() + $injection_class = 'PluginDatainjection' . $system_name . 'AssetInjection'; + + // Only create if not already registered + if (!isset($INJECTABLE_TYPES[$injection_class])) { + $INJECTABLE_TYPES[$injection_class] = 'datainjection'; + } + } + } +} + +/** + * Register injection classes for each injectable asset definition + */ +function plugin_datainjection_creationInjectableAssets(): void +{ + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + if (!isset($CFG_GLPI['injectable_types']) || empty($CFG_GLPI['injectable_types'])) { + return; + } + + + // For each injectable asset definition, create and register a distinct class + foreach ($CFG_GLPI['injectable_types'] as $definition_id => $itemtype) { + $definition = AssetDefinition::getById($definition_id); + // Get the asset definition to extract the system name + if ($definition->getAssetClassName() === $itemtype) { + // Use the system name to create a nice class name + $system_name = ucfirst($definition->fields['system_name']);//strtolower() + $injection_class = 'PluginDatainjection' . $system_name . 'AssetInjection'; + + plugin_datainjection_createAssetInjectionClass($injection_class, $definition_id); + } + } +} + +/** + * Dynamically create an asset injection class + */ +function plugin_datainjection_createAssetInjectionClass(string $class_name, int $definition_id): void +{ + + // Check if class already exists + if (class_exists($class_name)) { + return; + } + + // Create the class dynamically (not final, so it can be extended) + $code = << Date: Thu, 7 May 2026 14:59:27 +0200 Subject: [PATCH 2/2] Add forget files --- src/Glpi/Asset/AssetInjection.php | 227 ++++++++++++++++++ .../Asset/Capacity/IsInjectableCapacity.php | 127 ++++++++++ 2 files changed, 354 insertions(+) create mode 100644 src/Glpi/Asset/AssetInjection.php create mode 100644 src/Glpi/Asset/Capacity/IsInjectableCapacity.php diff --git a/src/Glpi/Asset/AssetInjection.php b/src/Glpi/Asset/AssetInjection.php new file mode 100644 index 00000000..6d00a08b --- /dev/null +++ b/src/Glpi/Asset/AssetInjection.php @@ -0,0 +1,227 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Datainjection\Glpi\Asset; + +use Glpi\Asset\Asset; +use Glpi\Asset\AssetDefinition; +use Glpi\Asset\AssetDefinitionManager; +use PluginDatainjectionCommonInjectionLib; +use PluginDatainjectionInjectionInterface; +use Search; + +use function Safe\preg_replace; + +abstract class AssetInjection extends Asset implements PluginDatainjectionInjectionInterface +{ + protected static string $definition_system_name = ''; + protected static int $fixed_asset_definition_id = 0; + + public static function getAssetDefinitionID(): int + { + + // If a fixed ID is set (for dynamically created classes), use it + if (static::$fixed_asset_definition_id > 0) { + return static::$fixed_asset_definition_id; + } + + return 0; + } + + /** + * Get the first active asset definition to use as system name + */ + protected static function getAssetDefinitionSystemName(): string + { + // Get first active asset definition from the database + // This ensures we have a valid definition to use + $manager = AssetDefinitionManager::getInstance(); + foreach ($manager->getDefinitions() as $definition) { + if ($definition->fields['id'] == static::getAssetDefinitionID()) { + return $definition->fields['system_name']; + } + } + + // Fallback to a default if none found + return ''; + } + + public static function getTypeName($nb = 0) + { + $manager = AssetDefinitionManager::getInstance(); + foreach ($manager->getDefinitions() as $definition) { + if ($definition->fields['id'] == static::getAssetDefinitionID()) { + return $definition->fields['label']; + } + } + // Fallback to a default if none found + return ''; + } + + public static function getDefinition(): AssetDefinition + { + if (empty(static::$definition_system_name)) { + static::$definition_system_name = static::getAssetDefinitionSystemName(); + } + + return parent::getDefinition(); + } + + + public static function getVirtualType($classname = null) + { + return 'Glpi\\CustomAsset\\' . static::getAssetDefinitionSystemName() . 'Asset'; + } + + public static function getVirtualTable($classname = null) + { + return getTableForItemType(self::getVirtualType()); + } + + public static function getTable($classname = null) + { + return getTableForItemType(Asset::class); + } + + public static function canCreate(): bool + { + return true; + } + + public function isPrimaryType() + { + return true; + } + + public function connectedTo() + { + return []; + } + + public function isNullable($field) + { + return true; + } + + + public static function replaceTableName(array $data): array + { + foreach ($data as $key => $value) { + if (is_array($value)) { + $data[$key] = self::replaceTableName($value); // récursif + } else { + if ($value === self::getTable()) { + $data[$key] = self::getVirtualTable(); + } + } + } + return $data; + } + /** + * @see plugins/datainjection/inc/PluginDatainjectionInjectionInterface::getOptions() + */ + public function getOptions($primary_type = '') + { + + // Build search options manually to avoid registration checks + // $tab = Search::getOptions(static::class); + $tab = Search::getOptions(self::getVirtualType()); + + $tab = self::replaceTableName($tab); + unset($tab[4]); + unset($tab[40]); + + $tab2 = [ +// [ +// 'id' => '4', +// 'table' => 'glpi_assets_assettypes', +// 'field' => 'name', +// 'linkfield' => 'assets_assettypes_id', +// 'name' => __('Type'), +// 'datatype' => 'dropdown', +// 'injectable' => true, +// ], +// [ +// 'id' => '40', +// 'table' => 'glpi_assets_assetmodels', +// 'field' => 'name', +// 'linkfield' => 'assets_assetmodels_id', +// 'name' => __('Model'), +// 'datatype' => 'dropdown', +// 'injectable' => true, +// ], + [ + 'id' => '200', + 'table' => $this->getTable(), + 'field' => 'assets_assetdefinitions_id', + 'linkfield' => 'assets_assetdefinitions_id', + 'name' => AssetDefinition::getTypeName(), + 'datatype' => 'number', + 'massiveaction' => false, + 'injectable' => true, + ], + ]; + + $tab = array_merge($tab, $tab2); + //Remove some options because some fields cannot be imported + $blacklist = PluginDatainjectionCommonInjectionLib::getBlacklistedOptions(static::class); + $blacklist = []; + $notimportable = ['300', '301']; + $options['ignore_fields'] = array_merge($blacklist, $notimportable); + + return PluginDatainjectionCommonInjectionLib::addToSearchOptions($tab, $options ?? [], $this); + } + + + /** + * @param array $fields_toinject array + **/ + public function getValueForAdditionalMandatoryFields($fields_toinject = []) + { + $fields_toinject[self::getVirtualType()]['assets_assetdefinitions_id'] = static::getAssetDefinitionID(); + + return $fields_toinject; + } + + /** + * @see plugins/datainjection/inc/PluginDatainjectionInjectionInterface::addOrUpdateObject() + */ + public function addOrUpdateObject($values = [], $options = []) + { + + $lib = new PluginDatainjectionCommonInjectionLib($this, $values, $options); + $lib->processAddOrUpdate(); + return $lib->getInjectionResults(); + } +} diff --git a/src/Glpi/Asset/Capacity/IsInjectableCapacity.php b/src/Glpi/Asset/Capacity/IsInjectableCapacity.php new file mode 100644 index 00000000..96c9560e --- /dev/null +++ b/src/Glpi/Asset/Capacity/IsInjectableCapacity.php @@ -0,0 +1,127 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/datainjection + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Datainjection\Glpi\Asset\Capacity; + +use Glpi\Asset\AssetDefinitionManager; +use Glpi\Asset\Capacity\AbstractCapacity; +use Glpi\Asset\CapacityConfig; +use Override; + +final class IsInjectableCapacity extends AbstractCapacity +{ + #[Override] + public function getLabel(): string + { + return __('Injectable', 'datainjection'); + } + + #[Override] + public function getIcon(): string + { + return 'ti ti-download'; + } + + #[Override] + public function getDescription(): string + { + return __("Inject objects list"); + } + +// public function getCloneRelations(): array +// { +// return [ +// Infocom::class, +// ]; +// } +// +// public function isUsed(string $classname): bool +// { +// return parent::isUsed($classname) +// && $this->countAssetsLinkedToPeerItem($classname, Infocom::class) > 0; +// } + + #[Override] + public function getCapacityUsageDescription(string $classname): string + { +// return sprintf( +// __('Used by %1$s of %2$s assets'), +// $this->countAssetsLinkedToPeerItem($classname, Infocom::class), +// $this->countAssets($classname) +// ); + return ''; + } + + public function onClassBootstrap(string $classname, CapacityConfig $config): void + { + global $CFG_GLPI; + +// if (!isset($CFG_GLPI['injectable_types'])) { +// $CFG_GLPI['injectable_types'] = []; +// } + $manager = AssetDefinitionManager::getInstance(); + foreach ($manager->getDefinitions() as $definition) { + $itemtype = $definition->getAssetClassName(); + if ($itemtype == $classname) { + if (!in_array($classname, $CFG_GLPI['injectable_types'])) { + $CFG_GLPI['injectable_types'][$definition->fields['id']] = $classname; + } + } + } + + $this->registerToTypeConfig('injectable_types', $classname); + +// CommonGLPI::registerStandardTab($classname, Infocom::class, 50); + } + + public function onCapacityDisabled(string $classname, CapacityConfig $config): void + { + // Unregister from infocom types +// $this->unregisterFromTypeConfig('injectable_types', $classname); +// +// // Delete related infocom data +// $infocom = new Infocom(); +// $infocom->deleteByCriteria(['itemtype' => $classname], force: true, history: false); +// +// $infocom_search_options = Infocom::rawSearchOptionsToAdd($classname); +// +// // Clean history related to infocoms +// $this->deleteFieldsLogs($classname, $infocom_search_options); +// +// // Clean display preferences +// $this->deleteDisplayPreferences($classname, $infocom_search_options); + } + +// #[Override] +// public function onObjectInstanciation(Asset $object, CapacityConfig $config): void +// { +// $object->fields['_added_by_hasinjectablecapacity'] = 'abc'; +// } +}