From 3a7ee7e7040636934f37c4bb74cfeab27697e267 Mon Sep 17 00:00:00 2001 From: Alex Rock Ancelet Date: Fri, 11 Oct 2024 17:37:22 +0200 Subject: [PATCH] First draft of generic asset controller --- src/CommonGLPI.php | 14 +++ .../Asset/CommonAssetController.php | 102 ++++++++++++++++++ src/Software.php | 5 + .../search/asset/common_asset_list.html.twig | 10 ++ 4 files changed, 131 insertions(+) create mode 100644 src/Glpi/Controller/Asset/CommonAssetController.php create mode 100644 templates/search/asset/common_asset_list.html.twig diff --git a/src/CommonGLPI.php b/src/CommonGLPI.php index 27bb9dd05ea..3ef7d48b631 100644 --- a/src/CommonGLPI.php +++ b/src/CommonGLPI.php @@ -590,6 +590,20 @@ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) return ''; } + public static function getSectorizedDetails(): array + { + return []; + } + + public static function getHeaderParameters(): array + { + return [ + static::getTypeName(\Session::getPluralNumber()), + $_SERVER['PHP_SELF'], + ...static::getSectorizedDetails(), + ]; + } + /** * show Tab content * diff --git a/src/Glpi/Controller/Asset/CommonAssetController.php b/src/Glpi/Controller/Asset/CommonAssetController.php new file mode 100644 index 00000000000..92ab860e08b --- /dev/null +++ b/src/Glpi/Controller/Asset/CommonAssetController.php @@ -0,0 +1,102 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace Glpi\Controller\Asset; + +use Glpi\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Routing\Attribute\Route; + +final class CommonAssetController extends AbstractController +{ + #[Route("/asset/{type}/search", name: "asset_search")] + public function __invoke(Request $request): Response + { + $type = $request->attributes->getString('type'); + + $asset_class = $this->getAssetClass($type); + + if (!$asset_class) { + throw new NotFoundHttpException('No asset type found'); + } + + if (!$asset_class::canView()) { + throw new AccessDeniedHttpException(); + } + + return $this->render('search/asset/common_asset_list.html.twig', [ + 'asset_class' => $asset_class, + ]); + } + + /** + * @return class-string<\CommonDBTM>|null + */ + private function getAssetClass(string $type): ?string + { + $class = (new \DbUtils())->fixItemtypeCase($type); + + if ( + $class + && \class_exists($class) + && \is_subclass_of($class, \CommonDBTM::class) + ) { + return $this->normalizeClass($class); + } + + $namespacedClass = \preg_replace_callback('~\\\([a-z])~Uu', static fn($i) => '\\' . \ucfirst($i[1]), 'Glpi\\' . \str_replace('/', '\\', $class)); + + if ( + $namespacedClass + && \class_exists($namespacedClass) + && \is_subclass_of($namespacedClass, \CommonDBTM::class) + ) { + return $this->normalizeClass($namespacedClass); + } + + return null; + } + + private function normalizeClass(string $class): string + { + if (!\class_exists($class)) { + throw new \RuntimeException('Class "$class" does not exist.'); + } + + return (new \ReflectionClass($class))->getName(); + } +} diff --git a/src/Software.php b/src/Software.php index 78da974827e..0cfc904926e 100644 --- a/src/Software.php +++ b/src/Software.php @@ -252,6 +252,11 @@ public function getSpecificMassiveActions($checkitem = null) return $actions; } + public static function getSectorizedDetails(): array + { + return ['assets', 'software']; + } + public static function processMassiveActionsForOneItemtype( MassiveAction $ma, CommonDBTM $item, diff --git a/templates/search/asset/common_asset_list.html.twig b/templates/search/asset/common_asset_list.html.twig new file mode 100644 index 00000000000..32f8068e499 --- /dev/null +++ b/templates/search/asset/common_asset_list.html.twig @@ -0,0 +1,10 @@ + +{% set header_params = call(asset_class ~ '::getHeaderParameters') %} + +
{{ asset_class ~ '::getHeaderParameters' }}
+ +{{ call('Html::header', header_params) }} + +{{ call('Search::show', [asset_class]) }} + +{{ call('Html::footer') }}