diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index d1f521d0..b442e5b4 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -20,7 +20,7 @@ jobs: name: "Generate CI matrix" uses: "glpi-project/plugin-ci-workflows/.github/workflows/generate-ci-matrix.yml@v1" with: - glpi-version: "10.0.x" + glpi-version: "11.0.x" ci: name: "GLPI ${{ matrix.glpi-version }} - php:${{ matrix.php-version }} - ${{ matrix.db-image }}" needs: "generate-ci-matrix" diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 00000000..7a81c5ba --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,21 @@ +in(__DIR__) + ->name('*.php') + ->ignoreVCSIgnored(true); + +$config = new Config(); + +$rules = [ + '@PER-CS2.0' => true, + 'trailing_comma_in_multiline' => ['elements' => ['arguments', 'array_destructuring', 'arrays']], // For PHP 7.4 compatibility +]; + +return $config + ->setRules($rules) + ->setFinder($finder) + ->setUsingCache(false); diff --git a/.phpcs.xml b/.phpcs.xml deleted file mode 100644 index 6c5742f9..00000000 --- a/.phpcs.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - . - /.git/ - ^vendor/ - - - - - - - - - - - - diff --git a/.twig_cs.dist.php b/.twig_cs.dist.php new file mode 100644 index 00000000..6041bcf7 --- /dev/null +++ b/.twig_cs.dist.php @@ -0,0 +1,17 @@ +in(__DIR__ . '/templates') + ->name('*.html.twig') + ->ignoreVCSIgnored(true); + +return Config::create() + ->setFinder($finder) + ->setRuleSet(GlpiTwigRuleset::class) +; diff --git a/CHANGELOG.md b/CHANGELOG.md index e30aa4c0..d9bd5bc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased] +## [3.0.0 (Migration Only)] - 2025-30-09 -- Fix massive actions compatibility with Fields plugin +- GLPI 11 compatibility ## [2.14.14] - 2025-04-23 diff --git a/ajax/remove.txt b/ajax/remove.txt deleted file mode 100644 index 97732142..00000000 --- a/ajax/remove.txt +++ /dev/null @@ -1,3 +0,0 @@ -Vous pouvez effacer ce fichier sans dommages. - -You can safely remove this file. diff --git a/composer.json b/composer.json index 05b653c3..ac53a7ea 100644 --- a/composer.json +++ b/composer.json @@ -1,19 +1,20 @@ { "require": { - "php": ">=7.4" + "php": ">=8.2" }, "require-dev": { - "glpi-project/phpstan-glpi": "^1.1", - "glpi-project/tools": "^0.8.0", - "php-parallel-lint/php-parallel-lint": "^1.4", - "phpstan/phpstan": "^2.1", - "squizlabs/php_codesniffer": "^3.13" + "glpi-project/tools": "^0.8.0" }, "config": { "optimize-autoloader": true, "platform": { - "php": "7.4.0" + "php": "8.2.99" }, "sort-packages": true + }, + "autoload-dev": { + "psr-4": { + "Glpi\\Tools\\": "../../tools/src/" + } } } diff --git a/composer.lock b/composer.lock index 6425d1e6..67aaeadf 100644 --- a/composer.lock +++ b/composer.lock @@ -4,70 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4f3c8fd45c1590d3efd34bde0a7c463e", + "content-hash": "a3a3de4fba7ca124cc1e054dc3210d27", "packages": [], "packages-dev": [ - { - "name": "glpi-project/phpstan-glpi", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/glpi-project/phpstan-glpi.git", - "reference": "e98ef833abc1389a0cc69743db5b1f3a7dc8ccfe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/glpi-project/phpstan-glpi/zipball/e98ef833abc1389a0cc69743db5b1f3a7dc8ccfe", - "reference": "e98ef833abc1389a0cc69743db5b1f3a7dc8ccfe", - "shasum": "" - }, - "require": { - "php": ">=7.4", - "phpstan/phpstan": "^2.1", - "symfony/polyfill-php80": "^1.32" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.85", - "php-parallel-lint/php-parallel-lint": "^1.4", - "phpstan/phpstan-phpunit": "^2.0", - "phpunit/phpunit": "^9.6" - }, - "type": "phpstan-extension", - "extra": { - "phpstan": { - "includes": [ - "extension.neon" - ] - } - }, - "autoload": { - "psr-4": { - "PHPStanGlpi\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan rules for GLPI.", - "support": { - "issues": "https://github.com/glpi-project/phpstan-glpi/issues", - "source": "https://github.com/glpi-project/phpstan-glpi/tree/1.1.1" - }, - "time": "2025-08-11T13:48:13+00:00" - }, { "name": "glpi-project/tools", - "version": "0.8.0", + "version": "0.8.1", "source": { "type": "git", "url": "https://github.com/glpi-project/tools.git", - "reference": "7c2dcec105ed3427183bdfd382d785363aade436" + "reference": "cf182b1a6bd1a73c5c6469dbbd0edabf7cb5857e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/glpi-project/tools/zipball/7c2dcec105ed3427183bdfd382d785363aade436", - "reference": "7c2dcec105ed3427183bdfd382d785363aade436", + "url": "https://api.github.com/repos/glpi-project/tools/zipball/cf182b1a6bd1a73c5c6469dbbd0edabf7cb5857e", + "reference": "cf182b1a6bd1a73c5c6469dbbd0edabf7cb5857e", "shasum": "" }, "require": { @@ -110,145 +61,31 @@ "issues": "https://github.com/glpi-project/tools/issues", "source": "https://github.com/glpi-project/tools" }, - "time": "2025-08-26T10:18:38+00:00" - }, - { - "name": "php-parallel-lint/php-parallel-lint", - "version": "v1.4.0", - "source": { - "type": "git", - "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git", - "reference": "6db563514f27e19595a19f45a4bf757b6401194e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6db563514f27e19595a19f45a4bf757b6401194e", - "reference": "6db563514f27e19595a19f45a4bf757b6401194e", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": ">=5.3.0" - }, - "replace": { - "grogy/php-parallel-lint": "*", - "jakub-onderka/php-parallel-lint": "*" - }, - "require-dev": { - "nette/tester": "^1.3 || ^2.0", - "php-parallel-lint/php-console-highlighter": "0.* || ^1.0", - "squizlabs/php_codesniffer": "^3.6" - }, - "suggest": { - "php-parallel-lint/php-console-highlighter": "Highlight syntax in code snippet" - }, - "bin": [ - "parallel-lint" - ], - "type": "library", - "autoload": { - "classmap": [ - "./src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Jakub Onderka", - "email": "ahoj@jakubonderka.cz" - } - ], - "description": "This tool checks the syntax of PHP files about 20x faster than serial check.", - "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint", - "keywords": [ - "lint", - "static analysis" - ], - "support": { - "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues", - "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.4.0" - }, - "time": "2024-03-27T12:14:49+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "2.1.22", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/41600c8379eb5aee63e9413fe9e97273e25d57e4", - "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4", - "shasum": "" - }, - "require": { - "php": "^7.4|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2025-08-04T19:17:37+00:00" + "time": "2025-09-08T09:45:41+00:00" }, { "name": "psr/container", - "version": "1.1.2", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { "php": ">=7.4.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -275,142 +112,53 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" - }, - "time": "2021-11-05T16:50:12+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.13.2", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "Former lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "Current lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", - "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", - "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", - "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + "source": "https://github.com/php-fig/container/tree/2.0.2" }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-06-17T22:17:01+00:00" + "time": "2021-11-05T16:47:00+00:00" }, { "name": "symfony/console", - "version": "v5.4.47", + "version": "v6.4.25", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed" + "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed", - "reference": "c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed", + "url": "https://api.github.com/repos/symfony/console/zipball/273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", + "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/string": "^5.1|^6.0" + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" }, "conflict": { - "psr/log": ">=3", - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/lock": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -444,7 +192,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.47" + "source": "https://github.com/symfony/console/tree/v6.4.25" }, "funding": [ { @@ -455,29 +203,33 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-06T11:30:55+00:00" + "time": "2025-08-22T10:21:53+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.4", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918", - "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.1" }, "type": "library", "extra": { @@ -486,7 +238,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -511,7 +263,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -527,7 +279,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:11:13+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/polyfill-ctype", @@ -864,275 +616,28 @@ ], "time": "2024-12-23T08:48:59+00:00" }, - { - "name": "symfony/polyfill-php73", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", - "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.33.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-09T11:45:10+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-01-02T08:10:11+00:00" - }, - { - "name": "symfony/polyfill-php81", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-09T11:45:10+00:00" - }, { "name": "symfony/service-contracts", - "version": "v2.5.4", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f37b419f7aea2e9abf10abd261832cace12e3300" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300", - "reference": "f37b419f7aea2e9abf10abd261832cace12e3300", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1|^3" + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" }, - "suggest": { - "symfony/service-implementation": "" - }, "type": "library", "extra": { "thanks": { @@ -1140,13 +645,16 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1173,7 +681,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.4" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -1189,38 +697,39 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:11:13+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { "name": "symfony/string", - "version": "v5.4.47", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "136ca7d72f72b599f2631aca474a4f8e26719799" + "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/136ca7d72f72b599f2631aca474a4f8e26719799", - "reference": "136ca7d72f72b599f2631aca474a4f8e26719799", + "url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", + "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": ">=3.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0|^6.0" + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -1259,7 +768,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.47" + "source": "https://github.com/symfony/string/tree/v7.3.3" }, "funding": [ { @@ -1270,36 +779,39 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-11-10T20:33:58+00:00" + "time": "2025-08-25T06:35:40+00:00" }, { "name": "twig/twig", - "version": "v3.11.3", + "version": "v3.21.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "3b06600ff3abefaf8ff55d5c336cd1c4253f8c7e" + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/3b06600ff3abefaf8ff55d5c336cd1c4253f8c7e", - "reference": "3b06600ff3abefaf8ff55d5c336cd1c4253f8c7e", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3", - "symfony/polyfill-php80": "^1.22", - "symfony/polyfill-php81": "^1.29" + "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { + "phpstan/phpstan": "^2.0", "psr/container": "^1.0|^2.0", "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, @@ -1343,7 +855,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.11.3" + "source": "https://github.com/twigphp/Twig/tree/v3.21.1" }, "funding": [ { @@ -1355,7 +867,7 @@ "type": "tidelift" } ], - "time": "2024-11-07T12:34:41+00:00" + "time": "2025-05-03T07:21:55+00:00" } ], "aliases": [], @@ -1364,11 +876,11 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.4" + "php": ">=8.2" }, "platform-dev": {}, "platform-overrides": { - "php": "7.4.0" + "php": "8.2.99" }, "plugin-api-version": "2.6.0" } diff --git a/css/styles.css b/css/styles.css deleted file mode 100644 index 13117607..00000000 --- a/css/styles.css +++ /dev/null @@ -1,91 +0,0 @@ -/*! - * ------------------------------------------------------------------------- - * GenericObject plugin for GLPI - * ------------------------------------------------------------------------- - * - * LICENSE - * - * This file is part of GenericObject. - * - * GenericObject is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * GenericObject 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GenericObject. If not, see . - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -/* - * Menu entry wrapper - */ -.genericobject_menu_wrapper { - display: block; - position: relative; - margin: 0; - padding: 0; -} - -/* - * Icon positionning - */ -.genericobject_menu_icon { - height: 16px; - width: 16px; - vertical-align: middle; - display: inline-block; -} -.icon_preview { - height: 32px; - width: 32px; -} - -.icon_preview > .genericobject_menu_icon { - display: block; - margin: 0 auto; - height: initial; - width: initial; - max-height: 32px; - max-width: 32px; -} - -.genericobject_menu_text { - padding-left: 5px; - margin: 0; - display: inline-block; -} - - -/* - * Fields Form - */ - -.genericobject_fields.add_new { - width: 80%; -} - -.genericobject_fields.add_new td.label { - width: 20%; -} - -.genericobject_fields.add_new td.dropdown { - width: 100%; -} - -/* - * Type's Profile tab : specific alignment - */ - -.genericobject_type_profiles tr > td { - width : 10%; -} diff --git a/fields/field.constant.php b/fields/field.constant.php index ce9f489e..1560d07c 100644 --- a/fields/field.constant.php +++ b/fields/field.constant.php @@ -30,123 +30,123 @@ global $GO_FIELDS; -$GO_FIELDS['id']['name'] = __("ID"); +$GO_FIELDS['id']['name'] = __s("ID"); $GO_FIELDS['id']['input_type'] = 'text'; $GO_FIELDS['id']['massiveaction'] = false; -$GO_FIELDS['name']['name'] = __("Name"); +$GO_FIELDS['name']['name'] = __s("Name"); $GO_FIELDS['name']['field'] = 'name'; $GO_FIELDS['name']['input_type'] = 'text'; $GO_FIELDS['name']['autoname'] = true; -$GO_FIELDS['serial']['name'] = __("Serial number"); +$GO_FIELDS['serial']['name'] = __s("Serial number"); $GO_FIELDS['serial']['field'] = 'serial'; $GO_FIELDS['serial']['input_type'] = 'text'; -$GO_FIELDS['otherserial']['name'] = __("Inventory number"); +$GO_FIELDS['otherserial']['name'] = __s("Inventory number"); $GO_FIELDS['otherserial']['field'] = 'otherserial'; $GO_FIELDS['otherserial']['input_type'] = 'text'; $GO_FIELDS['otherserial']['autoname'] = true; -$GO_FIELDS['comment']['name'] = __("Comments"); +$GO_FIELDS['comment']['name'] = __s("Comments"); $GO_FIELDS['comment']['field'] = 'comment'; $GO_FIELDS['comment']['input_type'] = 'multitext'; -$GO_FIELDS['other']['name'] = __("Others"); +$GO_FIELDS['other']['name'] = __s("Others"); $GO_FIELDS['other']['input_type'] = 'text'; -$GO_FIELDS['creationdate']['name'] = __("Creation date"); +$GO_FIELDS['creationdate']['name'] = __s("Creation date"); $GO_FIELDS['creationdate']['input_type'] = 'date'; -$GO_FIELDS['expirationdate']['name'] = __("Expiration date"); +$GO_FIELDS['expirationdate']['name'] = __s("Expiration date"); $GO_FIELDS['expirationdate']['input_type'] = 'date'; -$GO_FIELDS['date_mod']['name'] = __("Last update"); +$GO_FIELDS['date_mod']['name'] = __s("Last update"); $GO_FIELDS['date_mod']['input_type'] = 'datetime'; -$GO_FIELDS['date_creation']['name'] = __('Creation date'); +$GO_FIELDS['date_creation']['name'] = __s('Creation date'); $GO_FIELDS['date_creation']['input_type'] = 'datetime'; -$GO_FIELDS['url']['name'] = __("URL"); +$GO_FIELDS['url']['name'] = __s("URL"); $GO_FIELDS['url']['field'] = 'url'; $GO_FIELDS['url']['input_type'] = 'text'; $GO_FIELDS['url']['datatype'] = 'weblink'; -$GO_FIELDS['types_id']['name'] = __("Type"); +$GO_FIELDS['types_id']['name'] = __s("Type"); $GO_FIELDS['types_id']['linkfield'] = 'type'; $GO_FIELDS['types_id']['input_type'] = 'dropdown'; // The 'isolated' dropdown type will create a isolated table for each type that will be assigned // with this field. $GO_FIELDS['types_id']['dropdown_type'] = 'isolated'; -$GO_FIELDS['models_id']['name'] = __("Model"); +$GO_FIELDS['models_id']['name'] = __s("Model"); $GO_FIELDS['models_id']['input_type'] = 'dropdown'; $GO_FIELDS['models_id']['dropdown_type'] = 'isolated'; -$GO_FIELDS['categories_id']['name'] = __("Category"); +$GO_FIELDS['categories_id']['name'] = __s("Category"); $GO_FIELDS['categories_id']['input_type'] = 'dropdown'; $GO_FIELDS['categories_id']['dropdown_type'] = 'isolated'; -$GO_FIELDS['entities_id']['name'] = __("Entity"); +$GO_FIELDS['entities_id']['name'] = __s("Entity"); $GO_FIELDS['entities_id']['input_type'] = 'dropdown'; $GO_FIELDS['entities_id']['massiveaction'] = false; -$GO_FIELDS['template_name']['name'] = __("Template name"); +$GO_FIELDS['template_name']['name'] = __s("Template name"); $GO_FIELDS['template_name']['input_type'] = 'text'; $GO_FIELDS['template_name']['massiveaction'] = false; -$GO_FIELDS['notepad']['name'] = _n('Note', 'Notes', 2); +$GO_FIELDS['notepad']['name'] = _sn('Note', 'Notes', 2); $GO_FIELDS['notepad']['input_type'] = 'multitext'; -$GO_FIELDS['is_recursive']['name'] = __("Child entities"); +$GO_FIELDS['is_recursive']['name'] = __s("Child entities"); $GO_FIELDS['is_recursive']['input_type'] = 'bool'; -$GO_FIELDS['is_deleted']['name'] = __("Item in the dustbin"); +$GO_FIELDS['is_deleted']['name'] = __s("Item in the dustbin"); $GO_FIELDS['is_deleted']['input_type'] = 'bool'; $GO_FIELDS['is_deleted']['massiveaction'] = false; -$GO_FIELDS['is_template']['name'] = __("Templates"); +$GO_FIELDS['is_template']['name'] = __s("Templates"); $GO_FIELDS['is_template']['input_type'] = 'bool'; $GO_FIELDS['is_template']['massiveaction'] = false; -$GO_FIELDS['is_global']['name'] = __("Management type"); +$GO_FIELDS['is_global']['name'] = __s("Management type"); $GO_FIELDS['is_global']['input_type'] = 'bool'; $GO_FIELDS['is_global']['massiveaction'] = false; -$GO_FIELDS['is_helpdesk_visible']['name'] = __("Associable to a ticket"); +$GO_FIELDS['is_helpdesk_visible']['name'] = __s("Associable to a ticket"); $GO_FIELDS['is_helpdesk_visible']['input_type'] = 'bool'; -$GO_FIELDS['ticket_tco']['name'] = __("TCO"); +$GO_FIELDS['ticket_tco']['name'] = __s("TCO"); $GO_FIELDS['ticket_tco']['input_type'] = 'decimal'; -$GO_FIELDS['locations_id']['name'] = __("Item location"); +$GO_FIELDS['locations_id']['name'] = __s("Item location"); $GO_FIELDS['locations_id']['input_type'] = 'dropdown'; -$GO_FIELDS['states_id']['name'] = __("Status"); +$GO_FIELDS['states_id']['name'] = __s("Status"); $GO_FIELDS['states_id']['input_type'] = 'dropdown'; -$GO_FIELDS['users_id']['name'] = __("User"); +$GO_FIELDS['users_id']['name'] = __s("User"); $GO_FIELDS['users_id']['input_type'] = 'dropdown'; -$GO_FIELDS['groups_id']['name'] = __("Group"); +$GO_FIELDS['groups_id']['name'] = __s("Group"); $GO_FIELDS['groups_id']['input_type'] = 'dropdown'; $GO_FIELDS['groups_id']['condition'] = ['is_itemgroup' => 1]; -$GO_FIELDS['manufacturers_id']['name'] = __("Manufacturer"); +$GO_FIELDS['manufacturers_id']['name'] = __s("Manufacturer"); $GO_FIELDS['manufacturers_id']['input_type'] = 'dropdown'; -$GO_FIELDS['users_id_tech']['name'] = __("Technician in charge"); +$GO_FIELDS['users_id_tech']['name'] = __s("Technician in charge"); $GO_FIELDS['users_id_tech']['input_type'] = 'dropdown'; -$GO_FIELDS['domains_id']['name'] = __("Domain"); +$GO_FIELDS['domains_id']['name'] = __s("Domain"); $GO_FIELDS['domains_id']['input_type'] = 'dropdown'; -$GO_FIELDS['contact']['name'] = __("Alternate username"); +$GO_FIELDS['contact']['name'] = __s("Alternate username"); $GO_FIELDS['contact']['input_type'] = 'text'; -$GO_FIELDS['contact_num']['name'] = __("Alternate username number"); +$GO_FIELDS['contact_num']['name'] = __s("Alternate username number"); $GO_FIELDS['contact_num']['input_type'] = 'text'; -$GO_FIELDS['groups_id_tech']['name'] = __("Group in charge"); +$GO_FIELDS['groups_id_tech']['name'] = __s("Group in charge"); $GO_FIELDS['groups_id_tech']['input_type'] = 'dropdown'; $GO_FIELDS['groups_id_tech']['condition'] = ['is_assign' => 1]; diff --git a/front/commondropdown.form.php b/front/commondropdown.form.php deleted file mode 100644 index 11c7cc1a..00000000 --- a/front/commondropdown.form.php +++ /dev/null @@ -1,43 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); - -if (isset($_REQUEST['itemtype'])) { - $itemtype = $_REQUEST['itemtype']; - if (class_exists($itemtype)) { - $dropdown = new $itemtype(); - include(GLPI_ROOT . "/front/dropdown.common.form.php"); - } else { - Html::displayErrorAndDie(__('The requested dropdown does not exists', 'genericobject')); - } -} else { - Html::displayErrorAndDie(__('Not Found!')); -} diff --git a/front/commondropdown.php b/front/commondropdown.php deleted file mode 100644 index 3597003e..00000000 --- a/front/commondropdown.php +++ /dev/null @@ -1,43 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); - -if (isset($_REQUEST['itemtype'])) { - $itemtype = $_REQUEST['itemtype']; - if (class_exists($itemtype)) { - $dropdown = new $itemtype(); - include(GLPI_ROOT . "/front/dropdown.common.php"); - } else { - Html::displayErrorAndDie(__('The requested dropdown does not exists', 'genericobject')); - } -} else { - Html::displayErrorAndDie(__('Not Found!')); -} diff --git a/front/commontreedropdown.form.php b/front/commontreedropdown.form.php deleted file mode 100644 index 11c7cc1a..00000000 --- a/front/commontreedropdown.form.php +++ /dev/null @@ -1,43 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); - -if (isset($_REQUEST['itemtype'])) { - $itemtype = $_REQUEST['itemtype']; - if (class_exists($itemtype)) { - $dropdown = new $itemtype(); - include(GLPI_ROOT . "/front/dropdown.common.form.php"); - } else { - Html::displayErrorAndDie(__('The requested dropdown does not exists', 'genericobject')); - } -} else { - Html::displayErrorAndDie(__('Not Found!')); -} diff --git a/front/commontreedropdown.php b/front/commontreedropdown.php deleted file mode 100644 index da2d6ff5..00000000 --- a/front/commontreedropdown.php +++ /dev/null @@ -1,32 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); -include("./commondropdown.php"); diff --git a/front/typefamily.form.php b/front/eol_info.php similarity index 77% rename from front/typefamily.form.php rename to front/eol_info.php index 3a94c818..291a4f74 100644 --- a/front/typefamily.form.php +++ b/front/eol_info.php @@ -28,7 +28,20 @@ * ------------------------------------------------------------------------- */ -include("../../../inc/includes.php"); +// Check if user has admin rights +Session::checkRight('config', READ); -$dropdown = new PluginGenericobjectTypeFamily(); -include(GLPI_ROOT . "/front/dropdown.common.form.php"); +/** @var array $CFG_GLPI */ +global $CFG_GLPI; + +Html::header( + __s('Genericobject End of Life Information', 'genericobject'), + $_SERVER['PHP_SELF'], + 'tools', + 'PluginGenericobjectEOLInfo', +); + +$eolInfo = new PluginGenericobjectEOLInfo(); +$eolInfo->showForm(); + +Html::footer(); diff --git a/front/familylist.php b/front/familylist.php deleted file mode 100644 index 3880052a..00000000 --- a/front/familylist.php +++ /dev/null @@ -1,70 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include('../../../inc/includes.php'); - -$family = new PluginGenericobjectTypeFamily(); - -if (!isset($_GET['id']) || !$family->getFromDB($_GET['id'])) { - Html::header( - __("Objects management", "genericobject"), - $_SERVER['PHP_SELF'], - "assets", - "genericobject" - ); - - echo ""; - echo ""; - echo "
" . __("Empty family", "genericobject") . "
"; -} else { - $family->getFromDB($_GET['id']); - Html::header( - __("Objects management", "genericobject"), - $_SERVER['PHP_SELF'], - "assets", - $family->getName() - ); - - echo ""; - $types = PluginGenericobjectTypeFamily::getItemtypesByFamily($_GET['id']); - echo ""; - foreach ($types as $type) { - $itemtype = $type['itemtype']; - if (Session::haveRight(PluginGenericobjectProfile::getProfileNameForItemtype($itemtype), READ)) { - echo ""; - } - } - echo "
" . Dropdown::getDropdownName("glpi_plugin_genericobject_typefamilies", $_GET['id']) . "
"; - echo ""; - echo $itemtype::getTypeName(); - echo "
"; -} - -Html::footer(); diff --git a/front/field.form.php b/front/field.form.php deleted file mode 100644 index 0c2f26d2..00000000 --- a/front/field.form.php +++ /dev/null @@ -1,63 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); -if (isset($_POST["delete"])) { - if (isset($_POST["fields"]) && count($_POST["fields"]) > 0) { - $type = new PluginGenericobjectType(); - $type->getFromDB($_POST["id"]); - $itemtype = $type->fields['itemtype']; - PluginGenericobjectType::registerOneType($itemtype); - - foreach ($_POST["fields"] as $field => $value) { - if ( - $type->can($_POST["id"], PURGE) - && $value == 1 - && PluginGenericobjectField::checkNecessaryFieldsDelete($itemtype, $field) - ) { - PluginGenericobjectField::deleteField(getTableForItemType($itemtype), $field); - Session::addMessageAfterRedirect(__("Field(s) deleted successfully", "genericobject"), true, INFO); - } - } - } -} else if (isset($_POST["add_field"])) { - $type = new PluginGenericobjectType(); - if ($_POST["new_field"] && $type->can($_POST["id"], UPDATE)) { - $itemtype = $type->fields['itemtype']; - PluginGenericobjectType::registerOneType($itemtype); - PluginGenericobjectField::addNewField(getTableForItemType($itemtype), $_POST["new_field"]); - Session::addMessageAfterRedirect(__("Field added successfully", "genericobject")); - } -} else if (isset($_POST['action'])) { - //Move field - PluginGenericobjectField::changeFieldOrder($_POST); -} - -Html::back(); diff --git a/front/getimpacticon.php b/front/getimpacticon.php deleted file mode 100644 index 6efe10e1..00000000 --- a/front/getimpacticon.php +++ /dev/null @@ -1,65 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); - -// Read itemtype -$itemtype = $_GET['itemtype'] ?? null; - -// Missing required parameter -if (empty($itemtype)) { - http_response_code(400); - die; -} - -// Find by itemtype -$type = new PluginGenericobjectType(); -if (!$type->getFromDBByCrit(['itemtype' => $itemtype])) { - http_response_code(400); - die; -} - -// Get filepath -$filepath = $type->getImpactIconFilePath(); -if ($filepath === null) { - http_response_code(404); - die; -} - -// Validate image -if (!Document::isImage($filepath)) { - http_response_code(400); - die; -} - -// Send image -header("Content-Type: " . mime_content_type($filepath)); -readfile($filepath); -die; diff --git a/front/migration_status.php b/front/migration_status.php new file mode 100644 index 00000000..0b472ab1 --- /dev/null +++ b/front/migration_status.php @@ -0,0 +1,78 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/genericobject + * ------------------------------------------------------------------------- + */ + +use Glpi\Application\View\TemplateRenderer; +use Glpi\Asset\AssetDefinition; + +// Check if user has admin rights +Session::checkRight('config', UPDATE); + +/** @var DBmysql $DB */ +global $DB; + +// Get all GenericObject types +$genericobject_types = []; +if ($DB->tableExists(PluginGenericobjectType::getTable())) { + $query = [ + 'SELECT' => ['itemtype', 'name'], + 'FROM' => PluginGenericobjectType::getTable(), + ]; + $request = $DB->request($query); + foreach ($request as $data) { + $genericobject_types[$data['name']] = $data; + } +} + +// Get all custom asset definitions +$customassets = []; +if ($DB->tableExists(AssetDefinition::getTable())) { + $query = [ + 'SELECT' => ['id', 'system_name', 'label', 'icon'], + 'FROM' => AssetDefinition::getTable(), + ]; + $request = $DB->request($query); + foreach ($request as $data) { + // If genericobject asset is migrated to native custom asset, count linked items + $customassets[$data['system_name']] = $data; + $customassets[$data['system_name']]['items'] = countElementsInTable('glpi_assets_assets', ['assets_assetdefinitions_id' => $data['id']]); + } +} + +// Display GLPI header +Html::header(__s('GenericObject Migration Status', 'genericobject'), '', "tools", "migration"); + +// Render the template content +TemplateRenderer::getInstance()->display('@genericobject/migration_status.html.twig', [ + 'genericobject_types' => $genericobject_types, + 'customassets' => $customassets, +]); + +// Display GLPI footer +Html::footer(); diff --git a/front/object.form.php b/front/object.form.php deleted file mode 100644 index f3cad980..00000000 --- a/front/object.form.php +++ /dev/null @@ -1,113 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); - -$itemtype = null; - -if (isset($_REQUEST['itemtype'])) { - $types = array_keys(PluginGenericobjectType::getTypes()); - - $requested_type = $_REQUEST['itemtype']; - $error = []; - - if (!in_array($requested_type, $types)) { - $error[] = __('The requested type has not been defined yet!'); - if (!PluginGenericobjectType::canCreate()) { - $error[] = __('Please ask your administrator to create this type of object'); - }; - } else if (!class_exists($requested_type)) { - $error[] = __('The generated files for the requested type of object are missing!'); - $error[] = __('You might need to regenerate the files under ' . GENERICOBJECT_DOC_DIR . '.'); - } - - if (count($error) > 0) { - Html::header(__('Type not found!')); - Html::displayErrorAndDie(implode('
', $error)); - } else { - $itemtype = $requested_type; - } -} - -if (!is_null($itemtype)) { - if (!isset($_REQUEST['id'])) { - $id = -1; - } else { - $id = $_REQUEST['id']; - } - - if (!isset($_GET["withtemplate"])) { - $_GET["withtemplate"] = ""; - } - - $item = new $itemtype(); - - if (isset($_POST["add"])) { - $item->check($id, CREATE); - $newID = $item->add($_POST); - - if ($_SESSION['glpibackcreated']) { - Html::redirect($itemtype::getFormURL() . "&id=" . $newID); - } else { - Html::back(); - } - } else if (isset($_POST["update"])) { - $item->check($id, UPDATE); - $item->update($_POST); - Html::back(); - } else if (isset($_POST["restore"])) { - $item->check($id, DELETE); - $item->restore($_POST); - Html::back(); - } else if (isset($_POST["purge"])) { - $item->check($id, PURGE); - $item->delete($_POST, 1); - $item->redirectToList(); - } else if (isset($_POST["delete"])) { - $item->check($id, DELETE); - $item->delete($_POST); - $item->redirectToList(); - } - $menu = PluginGenericobjectType::getFamilyNameByItemtype($_GET['itemtype']); - Html::header( - $itemtype::getTypeName(), - $_SERVER['PHP_SELF'], - "assets", - ($menu !== false ? $menu : $itemtype), - strtolower($itemtype) - ); - - $item->display($_GET, ['withtemplate' => $_GET["withtemplate"]]); - - Html::footer(); -} else { - Html::header(__('Access Denied!')); - Html::DisplayErrorAndDie(__("You can't access to this page directly!")); -} diff --git a/front/object.php b/front/object.php deleted file mode 100644 index de023a91..00000000 --- a/front/object.php +++ /dev/null @@ -1,46 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); - -if (isset($_GET['itemtype'])) { - Session::checkRight(PluginGenericobjectProfile::getProfileNameForItemtype($_GET['itemtype']), READ); - $menu = PluginGenericobjectType::getFamilyNameByItemtype($_GET['itemtype']); - Html::header( - __("Type of objects", "genericobject"), - $_SERVER['PHP_SELF'], - "assets", - ($menu !== false ? $menu : strtolower($_GET['itemtype'])), - strtolower($_GET['itemtype']) - ); - Search::Show($_GET['itemtype']); -} - -Html::footer(); diff --git a/front/profile.form.php b/front/profile.form.php deleted file mode 100644 index 9d6fdc25..00000000 --- a/front/profile.form.php +++ /dev/null @@ -1,54 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); -Session::checkRight("profile", UPDATE); - -_log($_POST); -$prof = new Profile(); - -/* save profile */ -if (isset($_POST['update_all_rights']) && isset($_POST['itemtype'])) { - $profiles = []; - foreach ($_POST as $key => $val) { - if (preg_match("/^profile_/", $key)) { - $id = preg_replace("/^profile_/", "", $key); - $profiles[$id] = [ - "id" => $id, - "_" . PluginGenericobjectProfile::getProfileNameForItemtype($_POST['itemtype']) => $val - ]; - } - } - _log($profiles); - foreach ($profiles as $profile_id => $input) { - $prof->update($input); - } -} -Html::redirect($_SERVER['HTTP_REFERER']); diff --git a/front/type.form.php b/front/type.form.php deleted file mode 100644 index 8df873df..00000000 --- a/front/type.form.php +++ /dev/null @@ -1,76 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); - -if (!isset($_GET["id"])) { - $_GET["id"] = ''; -} -$type = new PluginGenericobjectType(); -$extraparams = []; -if (isset($_POST["select"]) && $_POST["select"] == "all") { - $extraparams["selected"] = "checked"; -} - -if (isset($_POST["add"])) { - //Add a new itemtype - $new_id = $type->add($_POST); - Html::redirect(Toolbox::getItemTypeFormURL('PluginGenericobjectType') . "?id=$new_id"); -} else if (isset($_POST["update"])) { - //Update an existing itemtype - if (isset($_POST['itemtypes']) && is_array($_POST['itemtypes'])) { - $_POST['linked_itemtypes'] = json_encode($_POST['itemtypes']); - } - $type->update($_POST); - Html::back(); -} else if (isset($_POST["purge"])) { - //Delete an itemtype - $type->delete($_POST); - $type->redirectToList(); -} else if (isset($_POST['regenerate'])) { - //Regenerate files for an itemtype - $type->getFromDB($_POST["id"]); - PluginGenericobjectType::checkClassAndFilesForOneItemType( - $type->fields['itemtype'], - $type->fields['name'], - true - ); - Html::back(); -} - -Html::header( - __("Objects management", "genericobject"), - $_SERVER['PHP_SELF'], - "config", - "PluginGenericobjectType" -); -$type->display($_GET); - -Html::footer(); diff --git a/front/type.php b/front/type.php deleted file mode 100644 index 74c4b6a0..00000000 --- a/front/type.php +++ /dev/null @@ -1,54 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); - -if ( - isset($_GET['itemtype']) - && !isset($_GET['search']) - && !isset($_GET['sort']) -) { - $type = new PluginGenericobjectType(); - $type->getFromDBByType($_GET['itemtype']); - Html::redirect(Toolbox::getItemTypeFormURL('PluginGenericobjectType') . '?id=' . $type->getID()); -} else if (Session::haveRightsOr('plugin_genericobject_types', [READ, CREATE, UPDATE, PURGE])) { - Html::header( - __("Type of objects", "genericobject"), - $_SERVER['PHP_SELF'], - "config", - "PluginGenericobjectType" - ); - Search::Show('PluginGenericobjectType'); - Html::footer(); -} else { - /** @var array $CFG_GLPI */ - global $CFG_GLPI; - Html::redirect($CFG_GLPI['root_doc'] . "/front/central.php"); -} diff --git a/front/typefamily.php b/front/typefamily.php deleted file mode 100644 index 51bd93bc..00000000 --- a/front/typefamily.php +++ /dev/null @@ -1,34 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -include("../../../inc/includes.php"); - -$dropdown = new PluginGenericobjectTypeFamily(); -include(GLPI_ROOT . "/front/dropdown.common.php"); diff --git a/hook.php b/hook.php index 4ead38bf..90a3b519 100644 --- a/hook.php +++ b/hook.php @@ -28,54 +28,6 @@ * ------------------------------------------------------------------------- */ -function plugin_genericobject_AssignToTicket($types) -{ - foreach (PluginGenericobjectType::getTypes() as $tmp => $value) { - $itemtype = $value['itemtype']; - if ($value['use_tickets']) { - if (class_exists($itemtype)) { - $types[$itemtype] = $itemtype::getTypeName(); - } else { - $types[$itemtype] = $itemtype; - } - } - } - return $types; -} - -// Define Dropdown tables to be manage in GLPI : -function plugin_genericobject_getDropdown() -{ - - $dropdowns = ['PluginGenericobjectTypeFamily' => PluginGenericobjectTypeFamily::getTypeName(2)]; - - $plugin = new Plugin(); - if ($plugin->isActivated("genericobject")) { - foreach (PluginGenericobjectType::getTypes() as $type) { - //_log($idx, var_export($type, true)); - $itemtype = $type['itemtype']; - PluginGenericobjectType::registerOneType($itemtype); - foreach (PluginGenericobjectType::getDropdownForItemtype($itemtype) as $table) { - $dropdown_itemtype = getItemTypeForTable($table); - if (class_exists($dropdown_itemtype)) { - $dropdowns[$dropdown_itemtype] = $dropdown_itemtype::getTypeName(); - } - } - } - } - return $dropdowns; -} - -function plugin_uninstall_addUninstallTypes($uninstal_types = []) -{ - foreach (PluginGenericobjectType::getTypes() as $tmp => $type) { - if ($type["use_plugin_uninstall"]) { - $uninstal_types[] = $type["itemtype"]; - } - } - return $uninstal_types; -} - //----------------------- INSTALL / UNINSTALL FUNCTION -------------------------------// /** @@ -93,11 +45,9 @@ function plugin_genericobject_install() foreach ( [ 'PluginGenericobjectField', - 'PluginGenericobjectCommonDropdown', - 'PluginGenericobjectCommonTreeDropdown', 'PluginGenericobjectProfile', 'PluginGenericobjectType', - 'PluginGenericobjectTypeFamily' + 'PluginGenericobjectTypeFamily', ] as $itemtype ) { if ($plug = isPluginItemType($itemtype)) { @@ -113,22 +63,15 @@ function plugin_genericobject_install() } } - if (!is_dir(GENERICOBJECT_CLASS_PATH)) { - @ mkdir(GENERICOBJECT_CLASS_PATH, 0755, true) - or die("Can't create folder " . GENERICOBJECT_CLASS_PATH); - } - - // Add icon directory + // Add icon directory $icons_dir = GLPI_PLUGIN_DOC_DIR . '/genericobject/impact_icons/'; if (!is_dir($icons_dir)) { mkdir($icons_dir); } - //Init plugin & types + //Init plugin plugin_init_genericobject(); - //Init profiles - PluginGenericobjectProfile::changeProfile(); return true; } @@ -145,7 +88,7 @@ function plugin_genericobject_uninstall() include_once(GENERICOBJECT_DIR . "/inc/object.class.php"); include_once(GENERICOBJECT_DIR . "/inc/type.class.php"); - //For each type + //For each type foreach (PluginGenericobjectType::getTypes(true) as $tmp => $value) { $itemtype = $value['itemtype']; if (class_exists($itemtype)) { @@ -158,7 +101,7 @@ function plugin_genericobject_uninstall() 'PluginGenericobjectType', 'PluginGenericobjectProfile', 'PluginGenericobjectField', - 'PluginGenericobjectTypeFamily' + 'PluginGenericobjectTypeFamily', ] as $itemtype ) { if ($plug = isPluginItemType($itemtype)) { @@ -172,66 +115,16 @@ function plugin_genericobject_uninstall() } } - // Delete all models of datainjection about genericobject + // Delete all models of datainjection about genericobject $table_datainjection_model = 'glpi_plugin_datainjection_models'; if ($DB->tableExists($table_datainjection_model)) { - $DB->query("DELETE FROM $table_datainjection_model WHERE itemtype LIKE 'PluginGenericobject%'"); + $DB->delete($table_datainjection_model, [ + 'itemtype' => ['LIKE', 'PluginGenericobject%'], + ]); } - // Invalidate menu data in current session + // Invalidate menu data in current session unset($_SESSION['glpimenu']); return true; } - -function plugin_datainjection_populate_genericobject() -{ - /** @var array $INJECTABLE_TYPES */ - global $INJECTABLE_TYPES; - $type = new PluginGenericobjectType(); - foreach ($type->find(['use_plugin_datainjection' => 1, 'is_active' => 1]) as $data) { - if (class_exists($data ['itemtype'] . "Injection")) { - $INJECTABLE_TYPES[$data ['itemtype'] . "Injection"] = 'genericobject'; - } - } -} - -function plugin_genericobject_MassiveActions($type) -{ - $types = PluginGenericobjectType::getTypes(); - if (isset($types[$type])) { - $objecttype = PluginGenericobjectType::getInstance($type); - if ($objecttype->isTransferable()) { - return ['PluginGenericobjectObject' . - MassiveAction::CLASS_ACTION_SEPARATOR . 'plugin_genericobject_transfer' => __("Transfer") - ]; - } else { - return []; - } - } else { - return []; - } -} - -function plugin_genericobject_MassiveActionsFieldsDisplay($options = []) -{ - if (!Plugin::isPluginActive('fields')) { - return false; - } - - if (!class_exists('PluginFieldsContainer') || !method_exists('PluginFieldsContainer', 'getEntries')) { - return false; - } - - if (!class_exists('PluginFieldsField') || !method_exists('PluginFieldsField', 'showSingle')) { - return false; - } - - $itemtypes = PluginFieldsContainer::getEntries('all'); - - if (in_array($options['itemtype'], $itemtypes)) { - return PluginFieldsField::showSingle($options['itemtype'], $options['options'], true); - } - - return false; -} diff --git a/inc/autoload.php b/inc/autoload.php index f3627944..6f7d7662 100644 --- a/inc/autoload.php +++ b/inc/autoload.php @@ -41,8 +41,8 @@ public function __construct($options = null) public function setOptions($options) { - if (!is_array($options) && !($options instanceof \Traversable)) { - throw new \InvalidArgumentException(); + if (!is_array($options) && !($options instanceof Traversable)) { + throw new InvalidArgumentException(); } foreach ($options as $path) { @@ -79,11 +79,11 @@ public function autoload($classname) $filename = implode(".", [ $class_name, "class", - "php" + "php", ]); foreach ($this->paths as $path) { - $test = $path . DIRECTORY_SEPARATOR . $filename; + $test = $path . DIRECTORY_SEPARATOR . $filename; if (file_exists($test)) { return include_once($test); } diff --git a/inc/commondropdown.class.php b/inc/commondropdown.class.php index 0baeaa1f..ce6a68d6 100644 --- a/inc/commondropdown.class.php +++ b/inc/commondropdown.class.php @@ -33,19 +33,19 @@ class PluginGenericobjectCommonDropdown extends CommonDropdown //Get itemtype name public static function getTypeName($nb = 0) { - $class = get_called_class(); + $class = static::class; return dropdown_getTypeName($class, $nb); } public static function getFormURL($full = true) { - return Toolbox::getItemTypeFormURL(get_parent_class(get_called_class()), $full) . - "?itemtype=" . get_called_class(); + return Toolbox::getItemTypeFormURL(get_parent_class(static::class), $full) . + "?itemtype=" . static::class; } public static function getSearchURL($full = true) { - return Toolbox::getItemTypeSearchURL(get_parent_class(get_called_class()), $full) . - "?itemtype=" . get_called_class(); + return Toolbox::getItemTypeSearchURL(get_parent_class(static::class), $full) . + "?itemtype=" . static::class; } } diff --git a/inc/commontreedropdown.class.php b/inc/commontreedropdown.class.php index e5432ed4..3b8ed576 100644 --- a/inc/commontreedropdown.class.php +++ b/inc/commontreedropdown.class.php @@ -33,21 +33,21 @@ class PluginGenericobjectCommonTreeDropdown extends CommonTreeDropdown //Get itemtype name public static function getTypeName($nb = 0) { - $class = get_called_class(); + $class = static::class; return dropdown_getTypeName($class, $nb); } public static function getFormURL($full = true) { - _log("PluginGenericobjectCommonTreeDropdown::getFormURL", get_parent_class(get_called_class())); - return Toolbox::getItemTypeFormURL(get_parent_class(get_called_class()), $full) . - "?itemtype=" . get_called_class(); + _log("PluginGenericobjectCommonTreeDropdown::getFormURL", get_parent_class(static::class)); + return Toolbox::getItemTypeFormURL(get_parent_class(static::class), $full) . + "?itemtype=" . static::class; } public static function getSearchURL($full = true) { - _log("PluginGenericobjectCommonTreeDropdown::getSearchURL", get_parent_class(get_called_class())); - return Toolbox::getItemTypeSearchURL(get_parent_class(get_called_class()), $full) . - "?itemtype=" . get_called_class(); + _log("PluginGenericobjectCommonTreeDropdown::getSearchURL", get_parent_class(static::class)); + return Toolbox::getItemTypeSearchURL(get_parent_class(static::class), $full) . + "?itemtype=" . static::class; } } diff --git a/inc/eolinfo.class.php b/inc/eolinfo.class.php new file mode 100644 index 00000000..3029d7c2 --- /dev/null +++ b/inc/eolinfo.class.php @@ -0,0 +1,127 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/genericobject + * ------------------------------------------------------------------------- + */ + +use Glpi\Application\View\TemplateRenderer; + +/** + * Class to display End of Life information for GenericObject + */ +class PluginGenericobjectEOLInfo extends CommonGLPI +{ + public static $rightname = 'config'; + + /** + * Get menu name + * + * @return string + */ + public static function getMenuName() + { + return __s('GenericObject EOL Info', 'genericobject'); + } + + /** + * Get menu content + * + * @return array + */ + public static function getMenuContent() + { + $menu = []; + + if (static::canView()) { + $menu['title'] = static::getMenuName(); + $menu['page'] = '/plugins/genericobject/front/eol_info.php'; + $menu['icon'] = 'ti ti-alert-triangle'; + $menu['links']['search'] = '/plugins/genericobject/front/eol_info.php'; + } + + return $menu; + } + + /** + * Check if user can view EOL info + * + * @return bool + */ + public static function canView(): bool + { + return Session::haveRight('config', READ); + } + + /** + * Get type name + * + * @param int $nb + * @return string + */ + public static function getTypeName($nb = 0) + { + return __s('GenericObject End of Life Information', 'genericobject'); + } + + /** + * Show EOL information form using Twig template + * + * @return void + */ + public function showForm() + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + TemplateRenderer::getInstance()->display('@genericobject/eol_info.html.twig', [ + 'plugin_version' => PLUGIN_GENERICOBJECT_VERSION, + 'plugin_web_dir' => $CFG_GLPI['root_doc'] . '/plugins/genericobject', + ]); + } + + /** + * Display EOL warning on central dashboard using Twig template + * + * @return void + */ + public static function displayCentralEOLWarning() + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + if (!static::canView()) { + return; + } + + $_SESSION['formcreator_eol_central_shown'] = true; + + TemplateRenderer::getInstance()->display('@genericobject/central_eol_warning.html.twig', [ + 'plugin_version' => PLUGIN_GENERICOBJECT_VERSION, + 'root_doc' => $CFG_GLPI['root_doc'], + ]); + } +} diff --git a/inc/field.class.php b/inc/field.class.php index 53cfd578..c3d635b9 100644 --- a/inc/field.class.php +++ b/inc/field.class.php @@ -30,170 +30,21 @@ class PluginGenericobjectField extends CommonDBTM { - /** - * - * Displat all fields present in DB for an itemtype - * @param $id the itemtype's id - */ - public static function showObjectFieldsForm($id) - { - /** - * @var array $GO_BLACKLIST_FIELDS - * @var array $GO_READONLY_FIELDS - * @var array $GO_FIELDS - */ - global $GO_BLACKLIST_FIELDS, $GO_READONLY_FIELDS, $GO_FIELDS; - - $url = Toolbox::getItemTypeFormURL(__CLASS__); - $object_type = new PluginGenericobjectType(); - $object_type->getFromDB($id); - $itemtype = $object_type->fields['itemtype']; - $fields_in_db = PluginGenericobjectSingletonObjectField::getInstance($itemtype); - $used_fields = []; - - //Reset fields definition only to keep the itemtype ones - $GO_FIELDS = []; - plugin_genericobject_includeCommonFields(true); - - PluginGenericobjectType::includeLocales($object_type->fields['name']); - PluginGenericobjectType::includeConstants($object_type->fields['name'], true); - - self::addReadOnlyFields($object_type); - - foreach ($GO_BLACKLIST_FIELDS as $autofield) { - if (!in_array($autofield, $used_fields)) { - $used_fields[$autofield] = $autofield; - } - } - - echo "
"; - echo "
"; - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - - $total = count($fields_in_db); - $global_index = $index = 1; - $haveCheckbox = false; - - foreach ($fields_in_db as $field => $value) { - $readonly = in_array($field, $GO_READONLY_FIELDS); - $blacklist = in_array($field, $GO_BLACKLIST_FIELDS); - - self::displayFieldDefinition($url, $itemtype, $field, $index, ($global_index == $total)); - - //All backlisted fields cannot be moved, and are listed first - if (!$readonly) { - $index++; - } - - if (!$blacklist && !$readonly) { - $haveCheckbox = true; - } - - //$table = getTableNameForForeignKeyField($field); - $used_fields[$field] = $field; - $global_index++; - } - echo "
"; - echo __("Fields associated with the object", "genericobject") . " : "; - echo $itemtype::getTypeName(); - echo "
" . __("Label", "genericobject") . "" . __("Name in DB", "genericobject") . "
"; - if ($haveCheckbox) { - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo "
"; - echo ""; - echo "" . __('Check all') . "/"; - echo "" . __('Uncheck all') . ""; - echo Html::submit(__("Delete permanently"), [ - 'name' => 'delete', - ]); - echo "
"; - } - - $dropdownFields = self::dropdownFields("new_field", $itemtype, $used_fields); - - if ($dropdownFields) { - echo "
"; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo "
" . __("Add new field", "genericobject") . ""; - echo $dropdownFields; - echo ""; - echo ""; - echo "
"; - } - - Html::closeForm(); - echo "
"; - } - - /** - * Method to set fields as read only, when the depend on some features - * that are enabled - * @since 0.85+2.4.0 - */ - public static function addReadOnlyFields(PluginGenericobjectType $type) - { - /** @var array $GO_READONLY_FIELDS */ - global $GO_READONLY_FIELDS; - - if ($type->canBeReserved()) { - $GO_READONLY_FIELDS[] = 'users_id'; - $GO_READONLY_FIELDS[] = 'locations_id'; - } - - if ($type->canUseGlobalSearch()) { - $GO_READONLY_FIELDS[] = 'serial'; - $GO_READONLY_FIELDS[] = 'otherserial'; - $GO_READONLY_FIELDS[] = 'locations_id'; - $GO_READONLY_FIELDS[] = 'states_id'; - $GO_READONLY_FIELDS[] = 'users_id'; - $GO_READONLY_FIELDS[] = 'groups_id'; - $GO_READONLY_FIELDS[] = 'manufacturers_id'; - $GO_READONLY_FIELDS[] = 'users_id_tech'; - } - - if ($type->canUseItemDevice()) { - $GO_READONLY_FIELDS[] = 'locations_id'; - } - } - /** - * Get the name of the field, as defined in a constant file - * The name may be the same, or not depending if it's an isolated dropdown or not - */ + /** + * Get the name of the field, as defined in a constant file + * The name may be the same, or not depending if it's an isolated dropdown or not + */ public static function getFieldName($field, $itemtype, $options, $remove_prefix = false) { /** @var DBmysql $DB */ global $DB; - $field_orig = $field; $field_table = null; - $input_type = isset($options['input_type']) - ? $options['input_type'] - : null; + $input_type = $options['input_type'] + ?? null; switch ($input_type) { case 'dropdown': - $dropdown_type = isset($options['dropdown_type']) - ? $options['dropdown_type'] - : null; + $dropdown_type = $options['dropdown_type'] + ?? null; $fk = getForeignKeyFieldForTable(getTableForItemType($itemtype)); if ($dropdown_type == 'isolated') { @@ -208,95 +59,25 @@ public static function getFieldName($field, $itemtype, $options, $remove_prefix //Prepend plugin's table prefix if this dropdown is not already handled by GLPI natively if ( - substr($field, 0, strlen('plugin_genericobject')) !== 'plugin_genericobject' - and ( - substr($field_table, strlen('glpi_')) - === substr($field, 0, strlen($field) - strlen('_id')) - ) - and !$DB->tableExists($field_table) + (!str_starts_with($field, 'plugin_genericobject') && substr($field_table, strlen('glpi_')) === substr($field, 0, strlen($field) - strlen('_id')) && !$DB->tableExists($field_table)) && !$remove_prefix ) { - if (!$remove_prefix) { - $field = 'plugin_genericobject_' . $field; - } + $field = 'plugin_genericobject_' . $field; } break; } return $field; } - /** - * - * Display a dropdown with all available fields for an itemtype - * @since - * @param string $name the dropdown name - * @param string $itemtype the itemtype - * @param array $used an array which contains all fields already added - * - * @return int the dropdown random ID - */ - public static function dropdownFields($name, $itemtype, $used = []) - { - /** @var array $GO_FIELDS */ - global $GO_FIELDS; - - $dropdown_types = []; - foreach ($GO_FIELDS as $field => $values) { - $message = ""; - $field_options = []; - $field = self::getFieldName($field, $itemtype, $values, false); - if (!in_array($field, $used)) { - if (!isset($dropdown_types[$field])) { - //Global management : - //meaning that a dropdown can be useful in all types (for example type, model, etc.) - if (isset($values['input_type']) && $values['input_type'] == 'dropdown') { - if (isset($values['entities_id'])) { - $field_options[] = __("Entity") . " : " . Dropdown::getYesNo($values['entities_id']); - if ($values['entities_id']) { - if (isset($values['is_recursive'])) { - $field_options[] = __("Child entities") . " : " . Dropdown::getYesNo($values['is_recursive']); - } - } - } else { - $field_options[] = __("Entity") . " : " . Dropdown::getYesNo(0); - } - if (isset($values['is_tree'])) { - $field_options[] = __("tree structure") . " : " . Dropdown::getYesNo($values['is_tree']); - } else { - $field_options[] = __("tree structure") . " : " . Dropdown::getYesNo(0); - } - //if (isset($values['isolated']) and $values['isolated']) { - // $field_options[] = __("Isolated") . " : ". Dropdown::getYesNo($values['isolated']); - //} else { - // $field_options[] = __("Isolated") . " : ". Dropdown::getYesNo(0); - //} - } - if (!empty($field_options)) { - $message = "(" . trim(implode(", ", $field_options)) . ")"; - } - } - $dropdown_types[$field] = $values['name'] . " " . $message; - } - } - - // Don't show dropdown empty - if (empty($dropdown_types)) { - return ''; - } - - ksort($dropdown_types); - return Dropdown::showFromArray($name, $dropdown_types, ['display' => false]); - } - - /** - * - * Get field's options defined in constant files. - * If this field has not been defined, it means that this field has been defined globally and - * must be dynamically created. - * - * @param $field the current field - * @param $itemtype the itemtype - * @return array which contains the full field definition - */ + /** + * + * Get field's options defined in constant files. + * If this field has not been defined, it means that this field has been defined globally and + * must be dynamically created. + * + * @param $field the current field + * @param $itemtype the itemtype + * @return array which contains the full field definition + */ public static function getFieldOptions($field, $itemtype = "") { /** @var array $GO_FIELDS */ @@ -305,275 +86,26 @@ public static function getFieldOptions($field, $itemtype = "") $options = []; $cleaned_field = preg_replace("/^plugin_genericobject_/", '', $field); if (!isset($GO_FIELDS[$cleaned_field]) && !empty($itemtype)) { - // This field has been dynamically defined because it's an isolated dropdown + // This field has been dynamically defined because it's an isolated dropdown $tmpfield = self::getFieldName( $field, $itemtype, [ 'dropdown_type' => 'isolated', - 'input_type' => 'dropdown' + 'input_type' => 'dropdown', ], - true + true, ); $options = $GO_FIELDS[$tmpfield]; $options['realname'] = $tmpfield; - } else if (isset($GO_FIELDS[$cleaned_field])) { + } elseif (isset($GO_FIELDS[$cleaned_field])) { $options = $GO_FIELDS[$cleaned_field]; $options['realname'] = $cleaned_field; } return $options; } - public static function displayFieldDefinition($target, $itemtype, $field, $index, $last = false) - { - /** - * @var array $CFG_GLPI - * @var array $GO_BLACKLIST_FIELDS - * @var array $GO_READONLY_FIELDS - */ - global $CFG_GLPI, $GO_BLACKLIST_FIELDS, $GO_READONLY_FIELDS; - - $readonly = in_array($field, $GO_READONLY_FIELDS); - $blacklist = in_array($field, $GO_BLACKLIST_FIELDS); - $options = self::getFieldOptions($field, $itemtype); - - echo ""; - echo ""; - if (!$blacklist && !$readonly) { - echo ""; - } else { - echo ""; - } - echo ""; - echo "" . __($options['name'], 'genericobject') . ""; - echo "" . $field . ""; - - echo ""; - if ((!$blacklist || $readonly) && $index > 1) { - Html::showSimpleForm( - $target, - $CFG_GLPI["root_doc"] . "/pics/deplier_up.png", - 'up', - ['field' => $field, 'action' => 'up', 'itemtype' => $itemtype], - $CFG_GLPI["root_doc"] . "/pics/deplier_up.png" - ); - } - echo ""; - - echo ""; - if ((!$blacklist || $readonly) && !$last) { - Html::showSimpleForm( - $target, - $CFG_GLPI["root_doc"] . "/pics/deplier_down.png", - 'down', - ['field' => $field, 'action' => 'down', 'itemtype' => $itemtype], - $CFG_GLPI["root_doc"] . "/pics/deplier_down.png" - ); - } - echo ""; - - echo ""; - } - - /** - * Add a new field in DB - * @param string $table the table - * @param string $field the field to delete - * @return void - */ - public static function addNewField($table, $field, $after = false) - { - /** @var DBmysql $DB */ - global $DB; - - _log("add", $field, "from", $table); - $itemtype = getItemTypeForTable($table); - if (!$DB->fieldExists($table, $field, false)) { - $options = self::getFieldOptions($field, $itemtype); - $query = "ALTER TABLE `$table` ADD `$field` "; - switch ($options['input_type']) { - case 'dropdown_yesno': - case 'dropdown_global': - case 'bool': - $query .= "TINYINT NOT NULL DEFAULT '0'"; - break; - case 'emptyspace': - case 'text': - $query .= "VARCHAR ( 255 ) NOT NULL DEFAULT ''"; - break; - case 'multitext': - $query .= "TEXT NULL"; - break; - case 'dropdown': - $query .= "INT unsigned NOT NULL DEFAULT '0'"; - break; - case 'integer': - $query .= "INT NOT NULL DEFAULT '0'"; - break; - case 'date': - $query .= "DATE DEFAULT NULL"; - break; - case 'datetime': - $query .= "TIMESTAMP NULL DEFAULT NULL"; - break; - case 'float': - $query .= "FLOAT NOT NULL DEFAULT '0'"; - break; - case 'decimal': - $query .= "DECIMAL(20,4) NOT NULL DEFAULT '0.0000'"; - break; - } - if ($after) { - $query .= " AFTER `$after`"; - } - $DB->query($query); - - //Reload list of fields for this itemtype in the singleton - - $recursive = $entity_assign = $tree = false; - - $table = getTableNameForForeignKeyField($field); - - if ($table != '' && !$DB->tableExists($table)) { - //Cannot use standard methods because class doesn't exists yet ! - $name = str_replace("glpi_plugin_genericobject_", "", $table); - $name = getSingular($name); - - $options['linked_itemtype'] = $itemtype; - - PluginGenericobjectType::addNewDropdown( - $name, - 'PluginGenericobject' . ucfirst($name), - $options - ); - } - // Invalidate menu data in current session - unset($_SESSION['glpimenu']); - - PluginGenericobjectSingletonObjectField::getInstance($itemtype, true); - } - } - - /** - * Delete a field in DB - * @param string $table the table - * @param string $field the field to delete - * @return void - */ - public static function deleteField($table, $field) - { - /** @var DBmysql $DB */ - global $DB; - - //Remove field from displaypreferences - self::deleteDisplayPreferences($table, $field); - - //If field exists, drop it ! - if ($DB->fieldExists($table, $field)) { - $DB->query("ALTER TABLE `$table` DROP `$field`"); - } + public static function install(Migration $migration) {} - $table = getTableNameForForeignKeyField($field); - //If dropdown is managed by the plugin - if ($table != '' && preg_match('/plugin_genericobject_(.*)/', $table, $results)) { - //Delete dropdown table - $query = "DROP TABLE `$table`"; - $DB->query($query); - //Delete dropdown files & class - $name = getSingular($results[1]); - PluginGenericobjectType::deleteClassFile($name); - PluginGenericobjectType::deleteFormFile($name); - PluginGenericobjectType::deletesearchFile($name); - } - } - - public static function deleteDisplayPreferences($table, $field) - { - - $pref = new DisplayPreference(); - $itemtype = getItemTypeForTable($table); - $searchopt = Search::getCleanedOptions($itemtype); - foreach ($searchopt as $num => $option) { - if ( - (isset($option['field']) && ($option['field'] == $field)) - || (isset($option['field']) && $option['linkfield'] == $field) - ) { - $pref->deleteByCriteria([ - 'itemtype' => $itemtype, - 'num' => $num - ]); - break; - } - } - } - - /** - * Change field order in DB - * @params an array which contains the itemtype, the field to move and the action (up/down) - * @return void - */ - public static function changeFieldOrder($params = []) - { - /** @var DBmysql $DB */ - global $DB; - $itemtype = $params['itemtype']; - $field = $params['field']; - $table = getTableForItemType($itemtype); - $fields = PluginGenericobjectSingletonObjectField::getInstance($params['itemtype']); - - //If action is down, reverse array first - if ($params['action'] == 'down') { - $fields = array_reverse($fields); - } - - //Get array keys - $keys = array_keys($fields); - //Index represents current position of $field - $index = 0; - foreach ($keys as $id => $key) { - if ($key == $field) { - $index = $id; - } - } - //Get 2 positions before and move field - if ($params['action'] == 'down') { - $previous = $index - 1; - } else { - $previous = $index - 2; - } - - if (isset($keys[$previous])) { - $parent = $fields[$keys[$previous]]; - $query = "ALTER TABLE `$table` MODIFY `$field` " . $fields[$field]['Type']; - $query .= " AFTER `" . $fields[$keys[$previous]]['Field'] . "`"; - $DB->query($query) or die($DB->error()); - } - } - - public static function checkNecessaryFieldsDelete($itemtype, $field) - { - $type = new PluginGenericobjectType(); - $type->getFromDBByType($itemtype); - - if ($type->canUseNetworkPorts() && 'locations_id' == $field) { - return false; - } - /* - if ($type->fields['use_direct_connections']) { - foreach(['users_id','groups_id',' states_id','locations_id'] as $tmp_field) { - if ($tmp_field == $field) { - return false; - } - } - }*/ - return true; - } - - public static function install(Migration $migration) - { - } - - public static function uninstall() - { - } + public static function uninstall() {} } diff --git a/inc/functions.php b/inc/functions.php index eaf6ba0c..7b8122ba 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -36,16 +36,30 @@ */ function dropdown_getTypeName($class, $nb = 0) { + if (!class_exists($class, true)) { + return $class; + } + $fk = getForeignKeyFieldForTable(getTableForItemType($class)); + /** @var CommonDBTM $instance */ $instance = new $class(); - $options = PluginGenericobjectField::getFieldOptions($fk, $instance->linked_itemtype); - $dropdown_type = isset($options['dropdown_type']) - ? $options['dropdown_type'] - : null; + + $linked_itemtype = null; + if (property_exists($instance, 'linked_itemtype')) { + $linked_itemtype = $instance->linked_itemtype; + } + + $options = PluginGenericobjectField::getFieldOptions($fk, $linked_itemtype); + $dropdown_type = $options['dropdown_type'] + ?? null; $label = $options['name'] ?? "no-name"; - if (!is_null($dropdown_type) and $dropdown_type === 'isolated') { - $linked_itemtype_object = new $instance->linked_itemtype(); - $label .= " (" . __($linked_itemtype_object::getTypeName(), 'genericobject') . ")"; + if (!is_null($dropdown_type) && $dropdown_type === 'isolated' && !is_null($linked_itemtype)) { + if (!class_exists($linked_itemtype, true)) { + return $label; + } + /** @var CommonDBTM $linked_itemtype_object */ + $linked_itemtype_object = new $linked_itemtype(); + $label .= " (" . __s($linked_itemtype_object::getTypeName(), 'genericobject') . ")"; } if ($label != '') { return $label; @@ -72,18 +86,12 @@ function _log() $trace_file = str_replace("\\", "/", $trace[0]['file']); $filename = preg_replace("|^" . $glpi_root . "/" . Plugin::getPhpDir('genericobject', false) . "/|", "", $trace_file); } - if (count($trace) > 1) { - $caller = $trace[1]; - } else { - $caller = null; - } + $caller = count($trace) > 1 ? $trace[1] : null; $msg = _format_trace($trace, func_get_args()); $msg .= "\n"; $show_log = false; if ( - !is_null($caller) and - isset($caller['class']) and - in_array($caller['class'], $LOG_FILTER) + !is_null($caller) && isset($caller['class']) && in_array($caller['class'], $LOG_FILTER) ) { $callee = array_shift($trace); $show_log = true; @@ -123,9 +131,9 @@ function _format_trace($bt, $args) foreach ($args as $arg) { if (is_array($arg) || is_object($arg)) { $msg .= " " . str_replace("\n", "\n ", print_r($arg, true)); - } else if (is_null($arg)) { + } elseif (is_null($arg)) { $msg .= 'NULL '; - } else if (is_bool($arg)) { + } elseif (is_bool($arg)) { $msg .= ($arg ? 'true' : 'false') . ' '; } else { $msg .= $arg . ' '; diff --git a/inc/object.class.php b/inc/object.class.php index 8b3269a2..f35f09ad 100644 --- a/inc/object.class.php +++ b/inc/object.class.php @@ -27,1322 +27,21 @@ * @link https://github.com/pluginsGLPI/genericobject * ------------------------------------------------------------------------- */ + +use Glpi\Features\Clonable; + class PluginGenericobjectObject extends CommonDBTM { - use Glpi\Features\Clonable; + use Clonable; protected $objecttype; - //Internal field counter - private $cpt = 0; - - //Get itemtype name - public static function getTypeName($nb = 0) - { - /** @var array $LANG */ - global $LANG; - $class = get_called_class(); - //Datainjection : Don't understand why I need this trick : need to be investigated ! - if (preg_match("/Injection$/i", $class)) { - $class = str_replace("Injection", "", $class); - } - $item = new $class(); - //Itemtype name can be contained in a specific locale field : try to load it - PluginGenericobjectType::includeLocales($item->objecttype->fields['name']); - if (isset($LANG['genericobject'][$class][0])) { - $type_name = $LANG['genericobject'][$class][0]; - } else { - $type_name = $item->objecttype->fields['name']; - } - return ucwords($type_name); - } - - - public function __construct() - { - $class = get_called_class(); - if (class_exists($class)) { - $this->objecttype = PluginGenericobjectType::getInstance($class); - } - $this->dohistory = $this->canUseHistory(); - - if (preg_match("/PluginGenericobject(.*)/", $class, $results)) { - if (preg_match("/^(.*)y$/i", $results[1], $end_results)) { - static::$rightname = 'plugin_genericobject_' . strtolower($end_results[1]) . 'ies'; - } else if (preg_match("/^(.*)(ss|x)$/i", $results[1])) { - static::$rightname = 'plugin_genericobject_' . strtolower($results[1]) . 'es'; - } else { - static::$rightname = 'plugin_genericobject_' . strtolower($results[1]) . 's'; - } - } - - if ($this->canUseNotepad()) { - $this->usenotepad = true; - } - } - public function getCloneRelations(): array - { - return [ - Computer_Item::class, - Contract_Item::class, - Document_Item::class, - Infocom::class, - Item_Devices::class, - NetworkPort::class, - ]; - } - - - /** - * Display information on treeview plugin - * - * @params itemtype, id, pic, url, name - * - * @return array - **/ - public static function showGenericObjectTreeview($params) - { - /** @var array $CFG_GLPI */ - global $CFG_GLPI; - - if (array_key_exists($params['itemtype'], PluginGenericobjectType::getTypes())) { - $item = new $params['itemtype'](); - if ($item->getFromDB($params['id'])) { - $params['name'] = $item->fields["name"]; - $params['url'] = Plugin::getWebDir('genericobject') . "/front/object.form.php" . "?itemtype=" . $params['itemtype'] . "&id=" . $params['id']; - } - } - return $params; - } - - /** - * Display node search url on treeview plugin - * - * @params itemtype, id, pic, url, name - * - * @return array - **/ - public static function getParentNodeSearchUrl($params) - { - if (array_key_exists($params['itemtype'], PluginGenericobjectType::getTypes())) { - $item = new $params['itemtype'](); - $search = $item->rawSearchOptions(); - //get searchoption id for location_id - $index = ''; - foreach ($search as $key => $val) { - if (isset($val['table']) && $val['table'] === 'glpi_locations') { - $index = $key; - } - } - - $token = Session::getNewCSRFToken(); - - $params['searchurl'] = $params['itemtype']::getSearchURL() . "&is_deleted=0&criteria[0][field]=" . $index . "&criteria[0]" . "[searchtype]=equals&criteria[0][value]=" . $params['locations_id'] . "&search=Rechercher&start=0&_glpi_csrf_token=$token"; - return $params; - } - - return $params; - } - - public static function install() - { - } - - public static function uninstall() - { - } - - public static function registerType() - { - /** - * @var array $PLUGIN_HOOKS - * @var array $UNINSTALL_TYPES - * @var array $ORDER_TYPES - * @var array $CFG_GLPI - * @var array $GO_LINKED_TYPES - * @var array $GENINVENTORYNUMBER_TYPES - */ - global $PLUGIN_HOOKS, $UNINSTALL_TYPES, $ORDER_TYPES, $CFG_GLPI, $GO_LINKED_TYPES, $GENINVENTORYNUMBER_TYPES; - - $class = get_called_class(); - $item = new $class(); - $fields = PluginGenericobjectSingletonObjectField::getInstance($class); - $plugin = new Plugin(); - - PluginGenericobjectType::includeLocales($item->getObjectTypeName()); - PluginGenericobjectType::includeConstants($item->getObjectTypeName()); - - $options = [ - "document_types" => $item->canUseDocuments(), - "helpdesk_visible_types" => $item->canUseTickets(), - "linkgroup_types" => isset($fields["groups_id"]), - "linkuser_types" => isset($fields["users_id"]), - "linkgroup_tech_types" => isset($fields["groups_id_tech"]), - "linkuser_tech_types" => isset($fields["users_id_tech"]), - "ticket_types" => $item->canUseTickets(), - "infocom_types" => $item->canUseInfocoms(), - "networkport_types" => $item->canUseNetworkPorts(), - "reservation_types" => $item->canBeReserved(), - "contract_types" => $item->canUseContracts(), - "unicity_types" => $item->canUseUnicity(), - "location_types" => isset($fields['locations_id']), - "itemdevices_types" => $item->canUseItemDevice(), - "itemdevicememory_types" => $item->canUseItemDevice(), - "itemdevicepowersupply_types" => $item->canUseItemDevice(), - "itemdevicenetworkcard_types" => $item->canUseItemDevice(), - "itemdeviceharddrive_types" => $item->canUseItemDevice(), - "itemdevicebattery_types" => $item->canUseItemDevice(), - "itemdevicefirmware_types" => $item->canUseItemDevice(), - "itemdevicesimcard_types" => $item->canUseItemDevice(), - "itemdevicegeneric_types" => $item->canUseItemDevice(), - "itemdevicepci_types" => $item->canUseItemDevice(), - "itemdevicesensor_types" => $item->canUseItemDevice(), - "itemdeviceprocessor_types" => $item->canUseItemDevice(), - "itemdevicesoundcard_types" => $item->canUseItemDevice(), - "itemdevicegraphiccard_types" => $item->canUseItemDevice(), - "itemdevicemotherboard_types" => $item->canUseItemDevice(), - "itemdevicecamera_types" => $item->canUseItemDevice(), - - ]; - - $glpiVersion = new Plugin(); - $glpiVersion = $glpiVersion->getGlpiVersion(); - - if (version_compare($glpiVersion, "10.0.19", '>=')) { - $options["itemdevicedrive_types"] = $item->canUseItemDevice(); - $options["itemdevicecontrol_types"] = $item->canUseItemDevice(); - } - - Plugin::registerClass($class, $options); - - if (plugin_genericobject_haveRight($class, READ)) { - //Change url for adding a new object, depending on template management activation - if ($item->canUseTemplate()) { - //Template management is active - $add_url = "/front/setup.templates.php?itemtype=$class&add=1"; - $PLUGIN_HOOKS['submenu_entry']['genericobject']['options'][$class]['links']['template'] = "/front/setup.templates.php?itemtype=$class&add=0"; - } else { - //Template management is not active - $add_url = Toolbox::getItemTypeFormURL($class, false); - } - //Menu management - $PLUGIN_HOOKS['submenu_entry']['genericobject']['options'][$class]['title'] = $class::getTypeName(); - $PLUGIN_HOOKS['submenu_entry']['genericobject']['options'][$class]['page'] = Toolbox::getItemTypeSearchURL($class, false); - $PLUGIN_HOOKS['submenu_entry']['genericobject']['options'][$class]['links']['search'] = Toolbox::getItemTypeSearchURL($class, false); - - if (plugin_genericobject_haveRight($class, UPDATE)) { - $PLUGIN_HOOKS['submenu_entry']['genericobject']['options'][$class]['links']['add'] = $add_url; - } - - //Add configuration icon, if user has right - if (Session::haveRight('config', UPDATE)) { - $PLUGIN_HOOKS['submenu_entry']['genericobject']['options'][$class]['links']['config'] = Toolbox::getItemTypeSearchURL('PluginGenericobjectType', false) . "?itemtype=$class"; - } - - if ($item->canUsePluginUninstall()) { - if (!in_array($class, $UNINSTALL_TYPES)) { - array_push($UNINSTALL_TYPES, $class); - } - } - if ($item->canUsePluginSimcard()) { - if ($plugin->isActivated('simcard') && $plugin->isActivated('simcard')) { - //@phpstan-ignore-next-line - PluginSimcardSimcard_Item::registerItemtype($class); - } - } - if ($item->canUsePluginOrder()) { - if (!in_array($class, $ORDER_TYPES)) { - array_push($ORDER_TYPES, $class); - } - } - if ($item->canBeReserved()) { - //Manage name used for sector - //See object.form.php L101 - //it can be 'itemtype' name or 'family' name - if (($name = PluginGenericobjectType::getFamilyNameByItemtype($class)) === false) { - $name = $class; - } - //from define.php $CFG_GLPI['javascript']['assets'] seems to be computed only once (from start) - //need to add manually js for sector and itemtype/family - $CFG_GLPI['javascript']['assets'][strtolower($name)] = ['fullcalendar', 'reservations']; - } - - if ($item->canUseGlobalSearch()) { - if (!in_array($class, $CFG_GLPI['asset_types'])) { - array_push($CFG_GLPI['asset_types'], $class); - } - - if (!in_array($class, $CFG_GLPI['globalsearch_types'])) { - array_push($CFG_GLPI['globalsearch_types'], $class); - } - } - - if ($item->canUseDirectConnections()) { - if (!in_array($class, $GO_LINKED_TYPES)) { - array_push($GO_LINKED_TYPES, $class); - } - $items_class = $class . "_Item"; - $items_class::registerType(); - } - - if ($item->canUseProjects()) { - if (!in_array($class, $CFG_GLPI['project_asset_types'])) { - array_push($CFG_GLPI['project_asset_types'], $class); - } - } - - $plugin_gen_path = Plugin::getPhpDir('geninventorynumber'); - if ($item->canUsePluginGeninventorynumber()) { - if (!in_array($class, $GENINVENTORYNUMBER_TYPES)) { - include_once("$plugin_gen_path/inc/profile.class.php"); - //@phpstan-ignore-next-line - PluginGeninventorynumberConfigField::registerNewItemType($class); - array_push($GENINVENTORYNUMBER_TYPES, $class); - } - } else if ($plugin->isActivated('geninventorynumber')) { - include_once("$plugin_gen_path/inc/profile.class.php"); - //@phpstan-ignore-next-line - PluginGeninventorynumberConfigField::unregisterNewItemType($class); - } - } - - foreach (PluginGenericobjectType::getDropdownForItemtype($class) as $table) { - $itemtype = getItemTypeForTable($table); - if (class_exists($itemtype)) { - $item = new $itemtype(); - //If entity dropdown, check rights to view & create - if ($itemtype::canView()) { - $PLUGIN_HOOKS['submenu_entry']['genericobject']['options'][$itemtype]['links']['search'] = Toolbox::getItemTypeSearchURL($itemtype, false); - if ($itemtype::canCreate()) { - $PLUGIN_HOOKS['submenu_entry']['genericobject']['options'][$class]['links']['add'] = Toolbox::getItemTypeFormURL($class, false); - } - } - } - } - } - - public static function getMenuIcon($itemtype) - { - /** @var array $CFG_GLPI */ - global $CFG_GLPI; - $itemtype_table = getTableForItemType($itemtype); - $itemtype_shortname = preg_replace("/^glpi_plugin_genericobject_/", "", $itemtype_table); - $itemtype_icons = glob( - GENERICOBJECT_PICS_PATH . '/' . getSingular($itemtype_shortname) . ".*" - ); - $finfo = new finfo(FILEINFO_MIME); - $icon_found = null; - foreach ($itemtype_icons as $icon) { - if (preg_match("|^image/|", $finfo->file($icon))) { - $icon_found = preg_replace("|^" . GLPI_ROOT . "|", "", $icon); - } - } - if (!is_null($icon_found)) { - $icon_path = $CFG_GLPI['root_doc'] . $icon_found; - } else { - $icon_path = Plugin::getWebDir('genericobject') . "/pics/default-icon.png"; - } - return ""; - } - - public static function checkItemtypeRight($class, $right) - { - if (!is_null($class) and class_exists($class)) { - $right_name = PluginGenericobjectProfile::getProfileNameForItemtype( - $class - ); - - return Session::haveRight($right_name, $right); - } - } - - public static function canCreate() - { - $class = get_called_class(); - //Datainjection : Don't understand why I need this trick : need to be investigated ! - if (preg_match("/Injection$/i", $class)) { - $class = str_replace("Injection", "", $class); - } - return static::checkItemtypeRight($class, CREATE); - } - - public static function canView() - { - $class = get_called_class(); - return static::checkItemtypeRight($class, READ); - } - - public static function canUpdate() - { - $class = get_called_class(); - return static::checkItemtypeRight($class, UPDATE); - } - - public static function canDelete() - { - $class = get_called_class(); - return static::checkItemtypeRight($class, DELETE); - } - - public static function canPurge() - { - $class = get_called_class(); - return static::checkItemtypeRight($class, PURGE); - } - - public function defineTabs($options = []) - { - $tabs = []; - - $this->addDefaultFormTab($tabs); - - if (!$this->isNewItem()) { - // Register impact tab is enabled - if ($this->canUseImpact()) { - $this->addImpactTab($tabs, $options); - } - - if ($this->canUseNetworkPorts()) { - $this->addStandardTab('NetworkPort', $tabs, $options); - } - - if ($this->canUseItemDevice()) { - $this->addStandardTab('Item_Devices', $tabs, $options); - } - - if ($this->canUseInfocoms()) { - $this->addStandardTab('Infocom', $tabs, $options); - } - - if ($this->canUseContracts()) { - $this->addStandardTab('Contract_Item', $tabs, $options); - } - - if ($this->canUseDocuments()) { - $this->addStandardTab('Document_Item', $tabs, $options); - } - - if ($this->canUseTickets()) { - $this->addStandardTab('Ticket', $tabs, $options); - $this->addStandardTab('Item_Problem', $tabs, $options); - $this->addStandardTab('Change_Item', $tabs, $options); - } - - if ($this->canUseNotepad()) { - $this->addStandardTab('Notepad', $tabs, $options); - } - - if ($this->canBeReserved()) { - $this->addStandardTab('Reservation', $tabs, $options); - } - - if ($this->canUseHistory()) { - $this->addStandardTab('Log', $tabs, $options); - } - } - return $tabs; - } - - - //------------------------ CAN methods -------------------------------------// - - public function getObjectTypeName() - { - return $this->objecttype->getName(); - } - - public function canUseInfocoms() - { - return ($this->objecttype->canUseInfocoms() && Session::haveRight("infocom", READ)); - } - - public function canUseContracts() - { - return ($this->objecttype->canUseContracts() && Session::haveRight("contract", READ)); - } - - - public function canUseTemplate() - { - return $this->objecttype->canUseTemplate(); - } - - - public function canUseNotepad() - { - return $this->objecttype->canUseNotepad(); - } - - public function canUseUnicity() - { - // Disable unicity feature (for GLPI 0.85 onward) : see issue #16 - // Related code : search for #16 - // FIXME : The bug may be in GLPI itself - return ($this->objecttype->canUseUnicity() && Session::haveRight("config", READ)); - } - - - public function canUseDocuments() - { - return ($this->objecttype->canUseDocuments() && Session::haveRight("document", READ)); - } - - - public function canUseTickets() - { - return ($this->objecttype->canUseTickets()); - } - - - public function canUseGlobalSearch() - { - return ($this->objecttype->canUseGlobalSearch()); - } - - - public function canBeReserved() - { - return ( - $this->objecttype->canBeReserved() - and Session::haveRight(ReservationItem::$rightname, ReservationItem::RESERVEANITEM) - ); - } - - - public function canUseHistory() - { - return ($this->objecttype->canUseHistory()); - } - - - public function canUsePluginDataInjection() - { - return ($this->objecttype->canUsePluginDataInjection()); - } - - - public function canUsePluginPDF() - { - return ($this->objecttype->canUsePluginPDF()); - } - - - public function canUsePluginOrder() - { - return ($this->objecttype->canUsePluginOrder()); - } - - public function canUsePluginGeninventorynumber() - { - return ($this->objecttype->canUsePluginGeninventorynumber()); - } - - public function canUseNetworkPorts() - { - return ($this->objecttype->canUseNetworkPorts()); - } - - - public function canUseDirectConnections() - { - return ($this->objecttype->canUseDirectConnections()); - } - - public function canUseProjects() - { - return ($this->objecttype->canUseProjects()); - } - - - public function canUsePluginUninstall() - { - return ($this->objecttype->canUsePluginUninstall()); - } - - public function canUsePluginSimcard() - { - return ($this->objecttype->canUsePluginSimcard()); - } - - public function getLinkedItemTypesAsArray() - { - return $this->objecttype->getLinkedItemTypesAsArray(); - } - - public function canUseItemDevice() - { - return ($this->objecttype->canUseItemDevice()); - } - - public function canUseImpact() - { - return ($this->objecttype->canUseImpact()); - } - - public function title() - { - } - - - public function showForm($id, $options = [], $previsualisation = false) - { - if ($previsualisation) { - $canedit = true; - $this->getEmpty(); - } else { - if ($id > 0) { - $this->check($id, READ); - } else { - // Create item - $this->check(-1, CREATE); - $this->getEmpty(); - } - - $canedit = $this->can($id, UPDATE); - } - - if (isset($options['withtemplate']) && $options['withtemplate'] == 2) { - $template = "newcomp"; - } else if (isset($options['withtemplate']) && $options['withtemplate'] == 1) { - $template = "newtemplate"; - } else { - $template = false; - } - - $this->fields['id'] = $id; - $this->initForm($id, $options); - $this->showFormHeader($options); - - if ($previsualisation) { - echo "" . __("Object preview", "genericobject") . ": "; - $itemtype = $this->objecttype->fields['itemtype']; - echo $itemtype::getTypeName(); - echo ""; - } - - //Reset fields definition only to keep the itemtype ones - $GO_FIELDS = []; - plugin_genericobject_includeCommonFields(true); - PluginGenericobjectType::includeConstants($this->getObjectTypeName(), true); - - foreach (PluginGenericobjectSingletonObjectField::getInstance($this->objecttype->fields['itemtype']) as $field => $description) { - if ($field == "is_helpdesk_visible" && $id <= 0) { - $this->displayField($canedit, $field, 1, $template, $description); - } else { - $this->displayField($canedit, $field, $this->fields[$field], $template, $description); - } - } - $this->closeColumn(); - - if (!$previsualisation) { - $this->showFormButtons($options); - } else { - echo ""; - Html::closeForm(); - } - - return true; - } - - - public static function getFieldsToHide() - { - return ['id', 'is_recursive', 'is_template', 'template_name', 'is_deleted', - 'entities_id', 'notepad', 'date_mod', 'date_creation', 'ticket_tco' - ]; - } - - - public function displayField($canedit, $name, $value, $template, $description = []) - { - $searchoption = PluginGenericobjectField::getFieldOptions($name, get_called_class()); - - if ( - !empty($searchoption) - && !in_array($name, self::getFieldsToHide()) - ) { - if (isset($searchoption['input_type']) && 'emptyspace' === $searchoption['input_type']) { - $searchoption['name'] = " "; - $description['Type'] = 'emptyspace'; - } - - $this->startColumn(); - echo ''; - - // Keep only main column type by removing anything that is preceded by a space (e.g. " unsigned") - // or a parenthesis (e.g. "(255)"). - echo '
'; - $column_type = preg_replace('/^([a-z]+)([ (].+)*$/', '$1', $description['Type']); - switch ($column_type) { - case "int": - $fk_table = getTableNameForForeignKeyField($name); - if ($fk_table != '') { - $itemtype = getItemTypeForTable($fk_table); - $dropdown = new $itemtype(); - $parameters = ['name' => $name, 'value' => $value, 'comments' => true]; - if ($dropdown->isEntityAssign()) { - $parameters["entity"] = $this->fields['entities_id']; - } - if ($dropdown->maybeRecursive()) { - $parameters['entity_sons'] = true; - } - if (isset($searchoption['condition'])) { - $parameters['condition'] = $searchoption['condition']; - } - if ($dropdown instanceof User) { - $parameters['entity'] = $this->fields["entities_id"]; - $parameters['right'] = 'all'; - User::dropdown($parameters); - } else { - Dropdown::show($itemtype, $parameters); - } - } else { - $min = $max = $step = 0; - if (isset($searchoption['min'])) { - $min = $searchoption['min']; - } else { - $min = 0; - } - if (isset($searchoption['max'])) { - $max = $searchoption['max']; - } else { - $max = 100; - } - if (isset($searchoption['step'])) { - $step = $searchoption['step']; - } else { - $step = 1; - } - Dropdown::showNumber( - $name, - [ - 'value' => $value, - 'min' => $min, - 'max' => $max, - 'step' => $step - ] - ); - } - break; - - case "tinyint": - Dropdown::showYesNo($name, $value); - break; - - case "varchar": - if (isset($searchoption['autoname']) && $searchoption['autoname']) { - $objectName = autoName( - $this->fields[$name], - $name, - ($template === "newcomp"), - $this->getType(), - $this->fields["entities_id"] - ); - } else { - $objectName = $this->fields[$name]; - } - echo Html::input( - $name, - [ - 'value' => $objectName, - ] - ); - break; - - case "longtext": - case "text": - case "mediumtext": - echo ""; - break; - - case "emptyspace": - echo ' '; - break; - - case "date": - Html::showDateField( - $name, - [ - 'value' => $value, - 'maybeempty' => true, - 'canedit' => true - ] - ); - break; - - case "datetime": - case "timestamp": - Html::showDateTimeField( - $name, - [ - 'value' => $value, - 'timestep' => true, - 'maybeempty' => true - ] - ); - break; - - case "float": - case 'decimal': - echo ""; - break; - - default: - echo ""; - break; - } - echo '
'; - $this->endColumn(); - } - } - - - - /** - * Add a new column - **/ - public function startColumn() - { - if ($this->cpt == 0) { - echo '
'; - echo '
'; - echo '
'; - echo '
'; - echo '
'; - } - echo '
'; - - $this->cpt++; - } - - - - /** - * End a column - **/ - public function endColumn() - { - echo "
"; - } - - - - /** - * Close a column - **/ - public function closeColumn() - { - if ($this->cpt > 0) { - echo "
"; - } - } - - - public function prepareInputForAdd($input) - { - - //Template management - if (isset($input["id"]) && $input["id"] > 0) { - $input["_oldID"] = $input["id"]; - } - unset($input['id']); - unset($input['withtemplate']); - - return $input; - } - - - public function cleanDBonPurge() - { - $parameters = ['items_id' => $this->getID(), 'itemtype' => get_called_class()]; - $types = ['Computer_Item', 'ReservationItem', 'Document_Item', 'Infocom', 'Contract_Item']; - foreach ($types as $type) { - $item = new $type(); - $item->deleteByCriteria($parameters); - } - - foreach (['NetworkPort', 'Computer_Item', 'ReservationItem', 'ReservationItem', 'Document_Item', 'Infocom', 'Contract_Item', 'Item_Problem', 'Change_Item', 'Item_Project'] as $itemtype) { - $ip = new $itemtype(); - $ip->cleanDBonItemDelete(get_called_class(), $this->getID()); - } - } - - /** - * Display object preview form - * @param PluginGenericobjectType $type the object type - */ - public static function showPrevisualisationForm(PluginGenericobjectType $type) - { - $itemtype = $type->fields['itemtype']; - $item = new $itemtype(); - - $right_name = PluginGenericobjectProfile::getProfileNameForItemtype( - $itemtype - ); - - if (Session::haveRight($right_name, READ) && Session::haveRight($right_name, CREATE)) { - $item->showForm(-1, [], true); - } else { - echo "
" . __( - "You must configure rights to enable the preview", - "genericobject" - ) . "
"; - } - } - - public function rawSearchOptions() - { - $datainjection_blacklisted = ['id', 'date_mod', 'entities_id', 'date_creation']; - $index_exceptions = ['name' => 1, 'id' => 2, 'completename' => 3, 'comment' => 16, 'date_mod' => 19, - 'entities_id' => 80, 'is_recursive' => 86, 'notepad' => 90, - 'date_creation' => 121 - ]; - - // Don't use indexes blacklisted by other item types in plugin DataInjection. - $plugin = new Plugin(); - if ( - $plugin->isActivated("datainjection") - && class_exists('PluginDatainjectionCommonInjectionLib') - ) { - $blacklisted_indexes = PluginDatainjectionCommonInjectionLib::getBlacklistedOptions( - get_called_class() //A class that extends PluginGenericobjectObject - ); - } else { - $blacklisted_indexes = []; - } - - $index = 3; - - $options = \Location::rawSearchOptionsToAdd(); - - $options[] = [ - 'id' => 'common', - 'name' => __('Characteristics'), - ]; - - $table = getTableForItemType(get_called_class()); - - // Prevent usage of reserved and blacklisted indexes - $taken_indexes = array_merge($index_exceptions, $blacklisted_indexes); - - plugin_genericobject_includeCommonFields(true); - - foreach (PluginGenericobjectSingletonObjectField::getInstance(get_called_class()) as $field => $values) { - $searchoption = PluginGenericobjectField::getFieldOptions( - $field, - $this->objecttype->fields['itemtype'] - ); - - if ($field == 'is_deleted') { - continue; - } - - //Some fields have fixed index values... - $currentindex = $index; - if (isset($index_exceptions[$field])) { - $currentindex = $index_exceptions[$field]; - } else { - //If this index is reserved, jump to next available one. - while (in_array($currentindex, $taken_indexes)) { - $currentindex++; - } - } - - $option = [ - 'id' => $currentindex, - ]; - $taken_indexes[] = $option['id']; - - $item = new $this->objecttype->fields['itemtype'](); - - //Table definition - //We test if it ends with s_id, in order to be sure that this pattern - //was found in a field that doesn't represent a foreign key - //for exemple a field called : is_identification - if (preg_match("/(s_id$|s_id_)/", $field)) { - $tmp = getTableNameForForeignKeyField($field); - } else { - $tmp = ''; - } - - if (preg_match("/(s_id_)/", $field)) { - $option['linkfield'] = $field; - } - - if ($tmp != '') { - $itemtype = getItemTypeForTable($tmp); - $tmpobj = new $itemtype(); - - //Set table - $option['table'] = $tmp; - - //Set field - if ($tmpobj instanceof CommonTreeDropdown) { - $option['field'] = 'completename'; - } else { - $option['field'] = 'name'; - } - } else { - $option['table'] = $table; - $option['field'] = $field; - } - - $option['name'] = $searchoption['name']; - - //Massive action or not - if (isset($searchoption['massiveaction'])) { - $option['massiveaction'] = $searchoption['massiveaction']; - } - - //Datainjection option - if (!in_array($field, $datainjection_blacklisted)) { - $option['injectable'] = 1; - } else { - $option['injectable'] = 0; - } - - //Field type - $column_type = preg_replace('/^([a-z]+)([ (].+)*$/', '$1', $values['Type']); - switch ($column_type) { - default: - case "varchar": - if ($field == 'name') { - $option['datatype'] = 'itemlink'; - $option['itemlink_type'] = get_called_class(); - $option['massiveaction'] = false; - // Enable autocomplete only for name, other fields may contains sensitive data - $option['autocomplete'] = true; - } else { - if (isset($searchoption['datatype']) && $searchoption['datatype'] == 'weblink') { - $option['datatype'] = 'weblink'; - } else { - $option['datatype'] = 'string'; - } - } - if ($item->canUsePluginDataInjection()) { - //Datainjection specific - $option['checktype'] = 'text'; - $option['displaytype'] = 'text'; - } - break; - case "tinyint": - $option['datatype'] = 'bool'; - if ($item->canUsePluginDataInjection()) { - //Datainjection specific - $option['displaytype'] = 'bool'; - } - break; - case "text": - case "longtext": - case "mediumtext": - $option['datatype'] = 'text'; - if ($item->canUsePluginDataInjection()) { - //Datainjection specific - $option['displaytype'] = 'multiline_text'; - } - break; - case "int": - if ($tmp != '') { - $option['datatype'] = 'dropdown'; - } else { - $option['datatype'] = 'integer'; - } - - if ($item->canUsePluginDataInjection()) { - if ($tmp != '') { - $option['displaytype'] = 'dropdown'; - $option['checktype'] = 'text'; - } else { - //Datainjection specific - $option['displaytype'] = 'dropdown_integer'; - $option['checktype'] = 'integer'; - } - } - break; - case "float": - case "decimal": - $option['datatype'] = $values['Type']; - if ($item->canUsePluginDataInjection()) { - //Datainjection specific - $option['display'] = 'text'; - $option['checktype'] = $values['Type']; - } - break; - case "date": - $option['datatype'] = 'date'; - if ($item->canUsePluginDataInjection()) { - //Datainjection specific - $option['displaytype'] = 'date'; - $option['checktype'] = 'date'; - } - break; - case "datetime": - case "timestamp": - $option['datatype'] = 'datetime'; - if ($item->canUsePluginDataInjection()) { - //Datainjection specific - $option['displaytype'] = 'date'; - $option['checktype'] = 'date'; - } - if ($field == 'date_mod') { - $option['massiveaction'] = false; - } - break; - } - - $options[] = $option; - - $index = $currentindex + 1; - } - - usort( - $options, - function ($a, $b) { - return ($a['id'] < $b['id']) ? -1 : 1; - } - ); - - return $options; - } - - - //Datainjection specific methods - public function isPrimaryType() - { - return true; - } - - - public function connectedTo() { return []; } + public static function install() {} - /** - * Standard method to add an object into glpi - * - * @param array $values fields to add into glpi - * @param array $options options used during creation - * @return array - * - **/ - public function addOrUpdateObject($values = [], $options = []) - { - //@phpstan-ignore-next-line - $lib = new PluginDatainjectionCommonInjectionLib($this, $values, $options); - $lib->processAddOrUpdate(); - return $lib->getInjectionResults(); - } - - - public function getOptions($primary_type = '') - { - return Search::getOptions($primary_type); - } - - - public function transfer($new_entity) - { - if ($this->fields['id'] > 0 && $this->fields['entities_id'] != $new_entity) { - //Update entity for this object - $tmp['id'] = $this->fields['id']; - $tmp['entities_id'] = $new_entity; - $this->update($tmp); - - $toupdate = ['id' => $this->fields['id']]; - foreach (PluginGenericobjectSingletonObjectField::getInstance(get_called_class()) as $field => $data) { - $table = getTableNameForForeignKeyField($field); - - //It is a dropdown table ! - if ( - $field != 'entities_id' - && $table != '' - && isset($this->fields[$field]) && $this->fields[$field] > 0 - ) { - //Instanciate a new dropdown object - $dropdown_itemtype = getItemTypeForTable($table); - $dropdown = new $dropdown_itemtype(); - $dropdown->getFromDB($this->fields[$field]); - - //If dropdown is only accessible in the other entity - //do not go further - if (!$dropdown->isEntityAssign() || in_array($new_entity, getAncestorsOf('glpi_entities', $dropdown->getEntityID()))) { - continue; - } else { - $tmp = []; - $where = []; - if ($dropdown instanceof CommonTreeDropdown) { - $tmp['completename'] = $dropdown->fields['completename']; - $where['completename'] = Toolbox::addslashes_deep($tmp['completename']); - } else { - $tmp['name'] = $dropdown->fields['name']; - $where['name'] = Toolbox::addslashes_deep($tmp['name']); - } - $tmp['entities_id'] = $new_entity; - $where['entities_id'] = $tmp['entities_id']; - //There's a dropdown value in the target entity - if ($found = $dropdown->find($where)) { - $myfound = array_pop($found); - if ($myfound['id'] != $this->fields[$field]) { - $toupdate[$field] = $myfound['id']; - } - } else { - $clone = $dropdown->fields; - if ($dropdown instanceof CommonTreeDropdown) { - unset($clone['completename']); - } - unset($clone['id']); - $clone['entities_id'] = $new_entity; - $new_id = $dropdown->import($clone); - $toupdate[$field] = $new_id; - } - } - } - } - $this->update($toupdate); - } - return true; - } - - /** - * @since version 0.85 - * - * @see CommonDBTM::showMassiveActionsSubForm() - **/ - public static function showMassiveActionsSubForm(MassiveAction $ma) - { - // KK TODO: check if MassiveAction itemtypes are concerned - //if (in_array ($options['itemtype'], $GENINVENTORYNUMBER_TYPES)) { - switch ($ma->getAction()) { - case "plugin_genericobject_transfer": - Dropdown::show('Entity', ['name' => 'new_entity']); - echo " "; - break; - default: - break; - } - //} - return true; - } - - // @codingStandardsIgnoreStart - public function plugin_genericobject_MassiveActionsProcess($data) - { - // @codingStandardsIgnoreEnd - /** @var DBmysql $DB */ - global $DB; - - switch ($data['action']) { - case 'plugin_genericobject_transfer': - $item = new $data['itemtype'](); - foreach ($data["item"] as $key => $val) { - if ($val == 1) { - $item->getFromDB($key); - $item->transfer($_POST['new_entity']); - } - } - break; - } - } - - public static function processMassiveActionsForOneItemtype( - MassiveAction $ma, - CommonDBTM $item, - array $ids - ) { - $results = [ - 'ok' => 0, - 'ko' => 0, - 'noright' => 0, - 'messages' => [] - ]; - - switch ($ma->action) { - case "plugin_genericobject_transfer": - foreach ($ma->items as $itemtype => $val) { - foreach ($val as $key => $item_id) { - $item = new $itemtype(); - $item->getFromDB($item_id); - $item->transfer($_POST['new_entity']); - $results['ok']++; - } - } - break; - - default: - break; - } - $ma->results = $results; - } - - public static function getMenuContent() - { - $types = PluginGenericobjectType::getTypes(); - $menu = []; - foreach ($types as $type) { - $itemtype = $type['itemtype']; - if (!class_exists($itemtype)) { - continue; - } - $item = new $itemtype(); - - $itemtype_rightname = PluginGenericobjectProfile::getProfileNameForItemtype($itemtype); - if ( - class_exists($itemtype) - && Session::haveRight($itemtype_rightname, READ) - ) { - $links = []; - $links['search'] = $itemtype::getSearchUrl(false); - $links['lists'] = ''; - - if ($item->canUseTemplate()) { - $links['template'] = "/front/setup.templates.php?itemtype=$itemtype&add=0"; - if (Session::haveRight($itemtype_rightname, CREATE)) { - $links['add'] = "/front/setup.templates.php?itemtype=$itemtype&add=1"; - } - } else { - if (Session::haveRight($itemtype_rightname, CREATE)) { - $links['add'] = $itemtype::getFormUrl(false); - } - } - - if ( - $type['plugin_genericobject_typefamilies_id'] > 0 - && (!isset($_GET['itemtype']) - || !preg_match("/itemtype=" . $_GET['itemtype'] . "/", $_GET['itemtype'])) - ) { - $family_id = $type['plugin_genericobject_typefamilies_id']; - $name = Dropdown::getDropdownName("glpi_plugin_genericobject_typefamilies", $family_id, 0, false); - $str_name = strtolower($name); - $menu[$str_name]['title'] = Dropdown::getDropdownName("glpi_plugin_genericobject_typefamilies", $family_id); - $menu[$str_name]['page'] = '/' . Plugin::getWebDir('genericobject', false) . '/front/familylist.php?id=' . $family_id; - $menu[$str_name]['options'][strtolower($itemtype)] = [ - 'title' => $type['itemtype']::getMenuName(), - 'page' => $itemtype::getSearchUrl(false), - 'links' => $links, - 'lists_itemtype' => $itemtype, - ]; - } else { - $menu[strtolower($itemtype)] = [ - 'title' => $type['itemtype']::getMenuName(), - 'page' => $itemtype::getSearchUrl(false), - 'links' => $links, - 'lists_itemtype' => $itemtype, - ]; - } - } - } - - // Sort by menu entries name - uasort($menu, fn($a, $b) => $a['title'] <=> $b['title']); - - // Mark as multi entries - $menu['is_multi_entries'] = true; - - return $menu; - } + public static function uninstall() {} } diff --git a/inc/object_item.class.php b/inc/object_item.class.php deleted file mode 100644 index ac86590e..00000000 --- a/inc/object_item.class.php +++ /dev/null @@ -1,138 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. - * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html - * @link https://github.com/pluginsGLPI/genericobject - * ------------------------------------------------------------------------- - */ - -// @codingStandardsIgnoreStart -class PluginGenericobjectObject_Item extends CommonDBChild -{ - // @codingStandardsIgnoreEnd - public $dohistory = true; - - // From CommonDBRelation - public static $itemtype_1 = "PluginGenericobjectObject"; - public static $items_id_1 = 'plugin_genericobject_objects_id'; - - public static $itemtype_2 = 'itemtype'; - public static $items_id_2 = 'items_id'; - - //Get itemtype name - public static function getTypeName($nb = 0) - { - /** @var array $LANG */ - global $LANG; - $class = get_called_class(); - //Datainjection : Don't understand why I need this trick : need to be investigated ! - if (preg_match("/Injection$/i", $class)) { - $class = str_replace("Injection", "", $class); - } - $item = new $class(); - //Itemtype name can be contained in a specific locale field : try to load it - PluginGenericobjectType::includeLocales($item->objecttype->fields['name']); - if (isset($LANG['genericobject'][$class][0])) { - return $LANG['genericobject'][$class][0]; - } else { - return $item->objecttype->fields['name']; - } - } - - public static function canView() - { - return Session::haveRight(self::$itemtype_1, READ); - } - - public static function canCreate() - { - return Session::haveRight(self::$itemtype_1, CREATE); - } - - /** - * - * Enter description here ... - * @since 2.2.0 - * @param CommonDBTM $item - */ - public static function showItemsForSource(CommonDBTM $item) - { - } - - /** - * - * Enter description here ... - * @since 2.2.0 - * @param CommonDBTM $item - */ - public static function showItemsForTarget(CommonDBTM $item) - { - } - - /** - * - * Enter description here ... - * @since 2.2.0 - */ - public static function registerType() - { - Plugin::registerClass(get_called_class(), ['addtabon' => self::getLinkedItemTypes()]); - } - - public static function getLinkedItemTypes() - { - $source_itemtype = self::getItemType1(); - $source_item = new $source_itemtype(); - return $source_item->getLinkedItemTypesAsArray(); - } - - public static function getItemType1() - { - $classname = get_called_class(); - return $classname::$itemtype_1; - } - - public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) - { - if (!$withtemplate) { - $itemtypes = self::getLinkedItemTypes(); - if (in_array(get_class($item), $itemtypes) || get_class($item) == self::getItemType1()) { - return [1 => __("Objects management", "genericobject")]; - } - } - return ''; - } - - public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) - { - $itemtypes = self::getLinkedItemTypes(); - if (get_class($item) == self::getItemType1()) { - self::showItemsForSource($item); - } else if (in_array(get_class($item), $itemtypes)) { - self::showItemsForTarget($item); - } - return true; - } -} diff --git a/inc/profile.class.php b/inc/profile.class.php index 988beb86..f8dd7e82 100644 --- a/inc/profile.class.php +++ b/inc/profile.class.php @@ -30,371 +30,17 @@ class PluginGenericobjectProfile extends Profile { - /* if profile deleted */ + /* if profile deleted */ public function cleanProfiles($id) { $this->deleteByCriteria(['id' => $id]); } - public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) - { - switch ($item->getType()) { - case 'Profile': - return self::createTabEntry(__('Objects management', 'genericobject')); - case 'PluginGenericobjectType': - return self::createTabEntry(_n('Profile', 'Profiles', 2)); - } - - return ''; - } - - public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) - { - switch ($item->getType()) { - case 'Profile': - $profile = new self(); - $profile->showForm($item->getID()); - break; - case 'PluginGenericobjectType': - _log($item); - self::showForItemtype($item); - break; - } - return true; - } - - public static function showForItemtype($type) - { - if (!Session::haveRight("profile", READ)) { - return false; - } - self::installRights(); - $canedit = Session::haveRight("profile", UPDATE); - - echo ""; - echo ""; - $itemtype = $type->fields['itemtype']; - echo ""; - - echo ""; - echo ""; - - if ($canedit) { - echo ""; - echo ""; - } - - echo "
"; - echo __("Rights assignment") . ": "; - echo $itemtype::getTypeName(); - echo "
"; - foreach (getAllDataFromTable(getTableForItemtype("Profile")) as $profile) { - $prof = new Profile(); - $prof->getFromDB($profile['id']); - $rights = [ - [ - 'label' => $profile['name'], - 'itemtype' => $itemtype, - 'field' => self::getProfileNameForItemtype($itemtype), - 'html_field' => "profile_" . $profile['id'], - ] - ]; - $prof->displayRightsChoiceMatrix( - $rights - ); - } - - echo "
"; - echo ""; - echo "
"; - Html::closeForm(); - } - public static function getProfileNameForItemtype($itemtype) { return preg_replace("/^glpi_/", "", getTableForItemType($itemtype)); } - - /* profiles modification */ - public function showForm($profiles_id, $options = []) - { - if (!Session::haveRight("profile", READ)) { - return false; - } - $canedit = Session::haveRight("profile", UPDATE); - - //Ensure rights are defined in database - self::installRights(); - - $profile = new Profile(); - $profile->getFromDB($profiles_id); - - echo ""; - echo ""; - - $general_rights = self::getGeneralRights(); - - $profile->displayRightsChoiceMatrix( - $general_rights, - [ - 'canedit' => $canedit, - 'default_class' => 'tab_bg_2', - 'title' => __('General', 'genericobject') - ] - ); - - $types_rights = self::getTypesRights(); - - $title = __('Objects', 'genericobject'); - if (count($types_rights) == 0) { - $title .= ' ' . __("(No types defined yet)", "genericobject"); - } - - $profile->displayRightsChoiceMatrix( - $types_rights, - [ - 'canedit' => $canedit, - 'default_class' => 'tab_bg_2', - 'title' => $title - ] - ); - $profile->showLegend(); - if ($canedit) { - echo "
"; - echo Html::hidden('id', ['value' => $profiles_id]); - echo Html::submit(_sx('button', 'Save'), ['name' => 'update']); - echo "
\n"; - Html::closeForm(); - } - echo ""; - - return true; - } - - public static function getProfileforItemtype($profiles_id, $itemtype) - { - $rights = ProfileRight::getProfileRights($profiles_id); - $itemtype_rightname = self::getProfileNameForItemtype($itemtype); - return isset($rights[$itemtype_rightname]) ? $rights[$itemtype_rightname] : 0; - } - - public function getProfilesFromDB($id, $config = true) - { - $prof_datas = []; - foreach ( - getAllDataFromTable( - getTableForItemType(__CLASS__), - ['profiles_id' => $id] - ) as $prof - ) { - if ($prof['right'] != "" || $config) { - $prof_datas[$prof['itemtype']] = $prof['right']; - $prof_datas[$prof['itemtype'] . '_open_ticket'] = $prof['open_ticket']; - $prof_datas['id'] = $prof['id']; - } - } - - if (empty($prof_datas) && !$config) { - return false; - } - - $prof_datas['profiles_id'] = $id; - $this->fields = $prof_datas; - - return true; - } - - public function saveProfileToDB($params) - { - /** @var DBmysql $DB */ - global $DB; - - $types = PluginGenericobjectType::getTypes(true); - if (!empty($types)) { - foreach ($types as $tmp => $profile) { - $query = "UPDATE `" . getTableForItemType(__CLASS__) . "` " . - "SET "; - - if (isset($params[$profile['itemtype']]) && $params[$profile['itemtype']] == 'NULL') { - $query .= "`right`='' "; - } else { - if (isset($params[$profile['itemtype']])) { - $query .= "`right`='" . $params[$profile['itemtype']] . "'"; - } else { - $query .= "`right`=''"; - } - } - - if (isset($params[$profile['itemtype'] . '_open_ticket'])) { - $query .= ", `open_ticket`='" . $params[$profile['itemtype'] . '_open_ticket'] . "' "; - } - - $query .= "WHERE `profiles_id`='" . $params['profiles_id'] . "' " . - "AND `itemtype`='" . $profile['itemtype'] . "'"; - $DB->query($query); - } - } - } - - - /** - * Create rights for the current profile - * @return void - */ - public static function createFirstAccess() - { - if (!self::profileExists($_SESSION["glpiactiveprofile"]["id"], 'PluginGenericobjectType')) { - self::createAccess($_SESSION["glpiactiveprofile"]["id"], "PluginGenericobjectType", true); - } - } - - /** - * Check if rights for a profile still exists - * @param int $profiles_id the profile ID - * @param string $itemtype name of the type - * @return bool - */ - public static function profileExists($profiles_id, $itemtype = false) - { - $profile = new Profile(); - $profile->getFromDB($profiles_id); - $rights = ProfileRight::getProfileRights($profiles_id); - $itemtype_rightname = self::getProfileNameForItemtype($itemtype); - if ($itemtype) { - _log( - "get rights on itemtype " . $itemtype . " for profile " . $profile->fields['name'], - ':', - isset($rights[$itemtype_rightname]) ? $rights[$itemtype_rightname] : "NONE" - ); - return (isset($rights[self::getProfileNameForItemtype($itemtype)])); - } - return true; - } - - /** - * Create rights for the profile if it doesn't exists - * @param int $profiles_id the profile ID - * @param string $itemtype - * @param bool $first - * @return void - */ - public static function createAccess($profiles_id, $itemtype, $first = false) - { - - $rights = getAllDataFromTable('glpi_profiles'); - $profile_right = new ProfileRight(); - $itemtype_rightname = self::getProfileNameForItemtype($itemtype); - - foreach ($rights as $right) { - if ($right['id'] == $profiles_id) { - $r = ALLSTANDARDRIGHT | READNOTE | UPDATENOTE; - } else { - $r = 0; - } - $profile_right->updateProfileRights($right['id'], [$itemtype_rightname => $r]); - } - } - - public static function getGeneralRights() - { - return [[ - 'itemtype' => 'PluginGenericobjectType', - 'label' => __("Type of objects", "genericobject"), - 'field' => self::getProfileNameForItemtype('PluginGenericobjectType'), - ] - ]; - } - - public static function getTypesRights() - { - $rights = []; - - include_once(GENERICOBJECT_DIR . "/inc/type.class.php"); - - $types = PluginGenericobjectType::getTypes(true); - if (count($types) > 0) { - foreach ($types as $_ => $type) { - $itemtype = $type['itemtype']; - - if (!class_exists($itemtype)) { - continue; - } - - $field = self::getProfileNameForItemtype($itemtype); - $objecttype = new PluginGenericobjectType($itemtype); - $rights[] = [ - 'itemtype' => $itemtype, - 'label' => $itemtype::getTypeName(), - 'field' => self::getProfileNameForItemtype($itemtype) - ]; - } - } - - return $rights; - } - - public static function installRights($first = false) - { - $missing_rights = []; - $installed_rights = ProfileRight::getAllPossibleRights(); - $right_names = []; - - // Add common plugin's rights - $right_names[] = self::getProfileNameForItemtype('PluginGenericobjectType'); - - // Add types' rights - $types = PluginGenericobjectType::getTypes(true); - foreach ($types as $_ => $type) { - $itemtype = $type['itemtype']; - $right_names[] = self::getProfileNameForItemtype($itemtype); - } - - // Check for already defined rights - foreach ($right_names as $right_name) { - _log($right_name, isset($installed_rights[$right_name])); - if (!isset($installed_rights[$right_name])) { - $missing_rights[] = $right_name; - } - } - - //Install missing rights in profile and update the object - if (count($missing_rights) > 0) { - ProfileRight::addProfileRights($missing_rights); - self::changeProfile(); - } - } - - /** - * Delete type from the rights - * @param string $itemtype the name of the type - * @return void - */ - public static function deleteTypeFromProfile($itemtype) - { - $rights = [self::getProfileNameForItemtype($itemtype)]; - ProfileRight::deleteProfileRights($rights); - } - - public static function changeProfile() - { - $general_rights = self::getGeneralRights(); - $type_rights = self::getTypesRights(); - $db_rights = ProfileRight::getProfileRights($_SESSION['glpiactiveprofile']['id']); - $rights = array_merge($general_rights, $type_rights); - - foreach ($rights as $right) { - $str_right = $right['field']; - if (preg_match("/plugin_genericobject_/", $str_right)) { - unset($_SESSION['glpiactiveprofile'][$str_right]); - if (!empty($db_rights) && isset($db_rights[$str_right])) { - $_SESSION['glpiactiveprofile'][$str_right] = $db_rights[$str_right]; - } - } - } - } - public static function install(Migration $migration) { /** @var DBmysql $DB */ @@ -403,7 +49,7 @@ public static function install(Migration $migration) $profileRight = new ProfileRight(); $profile = new Profile(); - //Update needed + //Update needed if ($DB->tableExists('glpi_plugin_genericobject_profiles')) { foreach (getAllDataFromTable('glpi_plugin_genericobject_profiles') as $right) { if (preg_match("/PluginGenericobject(.*)/", $right['itemtype'], $results)) { @@ -412,8 +58,8 @@ public static function install(Migration $migration) !countElementsInTable( 'glpi_profilerights', ['profiles_id' => $right['profiles_id'], - 'name' => $newrightname - ] + 'name' => $newrightname, + ], ) ) { switch ($right['right']) { @@ -432,20 +78,20 @@ public static function install(Migration $migration) $profileRight->add(['profiles_id' => $right['profiles_id'], 'name' => $newrightname, - 'rights' => $rightvalue + 'rights' => $rightvalue, ]); if ( !countElementsInTable( 'glpi_profilerights', ['profiles_id' => $right['profiles_id'], - 'name' => 'plugin_genericobject_types' - ] + 'name' => 'plugin_genericobject_types', + ], ) ) { $profileRight->add(['profiles_id' => $right['profiles_id'], 'name' => 'plugin_genericobject_types', - 'rights' => 23 + 'rights' => 23, ]); } } @@ -458,7 +104,7 @@ public static function install(Migration $migration) $helpdesk_item_types[] = $right['itemtype']; } } else { - $helpdesk_item_types = [$right['itemtype']]; + $helpdesk_item_types = [$right['itemtype']]; } $tmp['id'] = $profile->getID(); @@ -467,10 +113,7 @@ public static function install(Migration $migration) } } } - //$migration->dropTable('glpi_plugin_genericobject_profiles'); - } - if (!countElementsInTable('glpi_profilerights', ['name' => ['LIKE', '%genericobject%']])) { - self::createFirstAccess(); + //$migration->dropTable('glpi_plugin_genericobject_profiles'); } } @@ -478,8 +121,6 @@ public static function uninstall() { /** @var DBmysql $DB */ global $DB; - $query = "DELETE FROM `glpi_profilerights` - WHERE `name` LIKE '%plugin_genericobject%'"; - $DB->query($query) or die($DB->error()); + $DB->dropTable('glpi_profilerights'); } } diff --git a/inc/singletonobjectfield.class.php b/inc/singletonobjectfield.class.php index 76f6c650..c89468f1 100644 --- a/inc/singletonobjectfield.class.php +++ b/inc/singletonobjectfield.class.php @@ -33,23 +33,23 @@ // Purpose of file: // ---------------------------------------------------------------------- if (!defined('GLPI_ROOT')) { - die("Sorry. You can't access directly to this file"); + throw new RuntimeException('Direct access to this file is not allowed'); } class PluginGenericobjectSingletonObjectField { - /// Items list + /// Items list public static $_dbfields = []; - /** - * Singleton to store DB fields definition - * - * @since 2.1.0 - * @param itemtype itemtype to query - * @param reload reload db fields configuration from DB - * - * @return an array which contains DB fields definition - */ + /** + * Singleton to store DB fields definition + * + * @since 2.1.0 + * @param string $itemtype itemtype to query + * @param bool $reload reload db fields configuration from DB + * + * @return array an array which contains DB fields definition + */ public static function getInstance($itemtype, $reload = false) { /** @var DBmysql $DB */ diff --git a/inc/type.class.php b/inc/type.class.php index ed6d3790..376616a1 100644 --- a/inc/type.class.php +++ b/inc/type.class.php @@ -28,31 +28,33 @@ * ------------------------------------------------------------------------- */ +use Glpi\DBAL\QueryExpression; + class PluginGenericobjectType extends CommonDBTM { - const INACTIVE = 0; - const ACTIVE = 1; + public const INACTIVE = 0; + public const ACTIVE = 1; - const DRAFT = 0; - const PUBLISHED = 1; + public const DRAFT = 0; + public const PUBLISHED = 1; - const CLASS_TEMPLATE = "/objects/generic.class.tpl"; - const FORM_TEMPLATE = "/objects/generic.form.tpl"; - const CLASS_DROPDOWN_TEMPLATE = "/objects/generic.dropdown.class.tpl"; - const FRONTFORM_DROPDOWN_TEMPLATE = "/objects/front.form.tpl"; - const FRONT_DROPDOWN_TEMPLATE = "/objects/front.tpl"; - const SEARCH_TEMPLATE = "/objects/front.tpl"; - const AJAX_DROPDOWN_TEMPLATE = "/objects/dropdown.tabs.tpl"; - const AJAX_TEMPLATE = "/objects/ajax.tabs.tpl"; - const LOCALE_TEMPLATE = "/objects/locale.tpl"; - const OBJECTINJECTION_TEMPLATE = "/objects/objectinjection.class.tpl"; - const OBJECTITEM_TEMPLATE = "/objects/object_item.class.tpl"; + public const CLASS_TEMPLATE = "/objects/generic.class.tpl"; + public const FORM_TEMPLATE = "/objects/generic.form.tpl"; + public const CLASS_DROPDOWN_TEMPLATE = "/objects/generic.dropdown.class.tpl"; + public const FRONTFORM_DROPDOWN_TEMPLATE = "/objects/front.form.tpl"; + public const FRONT_DROPDOWN_TEMPLATE = "/objects/front.tpl"; + public const SEARCH_TEMPLATE = "/objects/front.tpl"; + public const AJAX_DROPDOWN_TEMPLATE = "/objects/dropdown.tabs.tpl"; + public const AJAX_TEMPLATE = "/objects/ajax.tabs.tpl"; + public const LOCALE_TEMPLATE = "/objects/locale.tpl"; + public const OBJECTINJECTION_TEMPLATE = "/objects/objectinjection.class.tpl"; + public const OBJECTITEM_TEMPLATE = "/objects/object_item.class.tpl"; - const CAN_OPEN_TICKET = 1024; + public const CAN_OPEN_TICKET = 1024; - public $dohistory = true; + public $dohistory = true; - public static $rightname = 'plugin_genericobject_types'; + public static $rightname = 'plugin_genericobject_types'; public function __construct($itemtype = false) @@ -69,7 +71,7 @@ public function isEntityAssign() public static function getTypeName($nb = 0) { - return __("Type of objects", "genericobject"); + return __s("Type of objects", "genericobject"); } public static function &getInstance($itemtype, $refresh = false) @@ -87,1133 +89,21 @@ public function getFromDBByType($itemtype) /** @var DBmysql $DB */ global $DB; - $query = "SELECT * FROM `" . getTableForItemType(__CLASS__) . "` " . - "WHERE `itemtype`='$itemtype'"; - $result = $DB->query($query); - if ($DB->numrows($result) > 0) { - $this->fields = $DB->fetchArray($result); - } else { - $this->getEmpty(); - } - } - - - //------------------------------------ Tabs management ----------------------------------- - public function defineTabs($options = []) - { - $tabs = []; - $this->addStandardTab(__CLASS__, $tabs, $options); - return $tabs; - } - - public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) - { - if (!$withtemplate) { - switch ($item->getType()) { - case __CLASS__: - // Number of fields in database - $itemtype = $item->fields['itemtype']; - $nb_fields = 0; - if (class_exists($itemtype)) { - $obj = new $itemtype(); - $obj->getEmpty(); - $nb_fields = count($obj->fields); - } - - $tabs = [ - 1 => __("Main"), - 3 => self::createTabEntry(_n("Field", "Fields", Session::getPluralNumber()), $nb_fields), - 5 => __("Preview") - ]; - if ($item->canUseDirectConnections()) { - $tabs[7] = __("Associated element"); - } - return $tabs; - } - } - return ''; - } - - public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) - { - if ($item->getType() == __CLASS__) { - switch ($tabnum) { - case 1: - $item->showBehaviorForm($item->getID()); - break; - - case 3: - PluginGenericobjectField::showObjectFieldsForm($item->getID()); - break; - - case 5: - PluginGenericobjectObject::showPrevisualisationForm($item); - break; - - case 6: - PluginGenericobjectProfile::showForItemtype($item); - break; - } - } - return true; - } - //------------------------------------- End tabs management ------------------------------ - - //------------------------------------- Framework hooks ---------------------------------- - public function prepareInputForAdd($input) - { - //Name must not be empty - if (isset($input['name']) && $input['name'] == '') { - Session::addMessageAfterRedirect(__("Type name is missing", "genericobject"), ERROR, true); - return []; - } - - // Name must be more than 1 char - if (isset($input['name']) && strlen($input['name']) < 2) { - Session::addMessageAfterRedirect(__("Type name must be longer", "genericobject"), ERROR, true); - return []; - } - - //Name must not match specific names - if (in_array($input['name'], ['field', 'object', 'type'])) { - Session::addMessageAfterRedirect(__( - "Types 'field', 'object' and 'type' are reserved. Please choose another one", - "genericobject" - ), ERROR, true); - return []; - } - - //Name must start with a letter - if (!preg_match("/^[a-zA-Z]+/i", $input['name'])) { - Session::addMessageAfterRedirect(__("Type must start with a letter", "genericobject"), ERROR, true); - return []; - } - $input['name'] = self::filterInput($input['name']); - - //Name must not be present in DB - if (countElementsInTable(getTableForItemType(__CLASS__), ['name' => $input['name']])) { - Session::addMessageAfterRedirect(__("A type already exists with the same name", "genericobject"), ERROR, true); - return []; - } else { - $input['itemtype'] = self::getClassByName($input['name']); - return $input; - } - } - - // @codingStandardsIgnoreStart - public function post_addItem() - { - // @codingStandardsIgnoreEnd - self::addNewObject( - $this->input["name"], - $this->input["itemtype"], - ['add_table' => 1, 'create_default_profile' => 1, 'overwrite_locales' => true] - ); - return true; - } - - public function prepareInputForUpdate($input) - { - // Handle impact_icon - $input = $this->handleImpactIconUpdate($input); - - // Handle use_impact - $input = $this->handleUseImpactUpdate($input); - - //If itemtype is active : register it ! - if (isset($input["is_active"]) && $input["is_active"]) { - self::registerOneType($this->fields['itemtype']); - } - return $input; - } - - public function handleImpactIconUpdate($input) - { - // Read submitted icon - $icon = $input['_impact_icon'][0] ?? null; - - // Icon wasn't submitted, nothing more to do - if (empty($icon)) { - return $input; - } - - // Convert to realpath - $icon_path = realpath(GLPI_TMP_DIR . "/$icon"); - - // Realpath didn't find the file, shouldn't really happenn but just in case - if (!$icon_path) { - return $input; - } - - // Wrong file type, ignore - if (!Document::isImage($icon_path)) { - return $input; - } - - // File is outside of GLPI_TMP_DIR - if (!str_starts_with($icon_path, realpath(GLPI_TMP_DIR))) { - trigger_error("Trying to read forbidden file: $icon_path", E_USER_WARNING); - return $input; - } - - // Reread base file name - $icon_filename = pathinfo($icon_path, PATHINFO_BASENAME); - - // Remove previous icon if exist - $existing_icon_path = self::getImpactIconFileStoragePath( - $this->fields['impact_icon'], - $this->fields['itemtype'] - ); - if ( - $existing_icon_path - && file_exists($existing_icon_path) - && str_starts_with( - realpath($existing_icon_path), - realpath(GLPI_PLUGIN_DOC_DIR . "/genericobject/impact_icons/") - ) - ) { - unlink($existing_icon_path); - } - - // Move file and update input on success - $icons_dir = GLPI_PLUGIN_DOC_DIR . '/genericobject/impact_icons/'; - if (!is_dir($icons_dir) && !mkdir($icons_dir)) { - trigger_error(sprintf('Unable to create "%s" directory.', $icons_dir), E_USER_WARNING); - return $input; - } - - $new_path = self::getImpactIconFileStoragePath( - $icon_filename, - $this->fields['itemtype'] - ); - if (rename($icon_path, $new_path)) { - $input['impact_icon'] = $icon_filename; - } - - return $input; - } - - public function handleUseImpactUpdate($input) - { - $use_impact = $input['use_impact'] ?? null; - unset($input['use_impact']); - - // Value wasn't modified, nothing to be done - if ($use_impact === null) { - return $input; - } - - // Impact analysis will now be enabled, update conf if needed - if ($use_impact && !Impact::isEnabled($this->fields['itemtype'])) { - $enabled = Config::getConfigurationValue('core', Impact::CONF_ENABLED); - $enabled = importArrayFromDB($enabled); - $enabled[] = $this->fields['itemtype']; - Config::setConfigurationValues('core', [ - Impact::CONF_ENABLED => exportArrayToDB($enabled) - ]); - return $input; - } - - // Impact analysis will now be disabled, update config if needed - if (!$use_impact && Impact::isEnabled($this->fields['itemtype'])) { - $enabled = Config::getConfigurationValue('core', Impact::CONF_ENABLED); - $enabled = importArrayFromDB($enabled); - $enabled = array_filter( - $enabled, - fn($i) => $i != $this->fields['itemtype'] - ); - Config::setConfigurationValues('core', [ - Impact::CONF_ENABLED => exportArrayToDB($enabled) - ]); - - return $input; - } - - return $input; - } - - // @codingStandardsIgnoreStart - public function post_updateItem($history = true) - { - // @codingStandardsIgnoreEnd - //Check if some fields need to be added, because of GLPI framework - $this->checkNecessaryFieldsUpdate(); - } - - // @codingStandardsIgnoreStart - public function pre_deleteItem() - { - // @codingStandardsIgnoreEnd - if ($this->getFromDB($this->fields["id"])) { - $name = $this->fields['name']; - $itemtype = $this->fields['itemtype']; - - //Delete all network ports - self::deleteNetworking($itemtype); - - //Drop all dropdowns associated with itemtype - self::deleteDropdownsForItemtype($itemtype); - - //Delete loans associated with this type - self::deleteLoans($itemtype); - - //Delete loans associated with this type - self::deleteUnicity($itemtype); - - //Delete reservations with this tyoe - self::deleteReservations($itemtype); - self::deleteReservationItems($itemtype); - - //Remove datainjection specific file - self::deleteInjectionFile($name); - - //Delete profile informations associated with this type - PluginGenericobjectProfile::deleteTypeFromProfile($itemtype); - - self::deleteTicketAssignation($itemtype); - - //Remove associations to simcards with this type - self::deleteSimcardAssignation($itemtype); - - //Remove existing datainjection models - self::removeDataInjectionModels($itemtype); - - //Delete specific locale directory - self::deleteLocales($name, $itemtype); - - self::deleteItemtypeReferencesInGLPI($itemtype); - - self::deleteItemTypeFilesAndClasses($name, $this->getTable(), $itemtype); - - //self::deleteNotepad($itemtype); - - if (preg_match("/PluginGenericobject(.*)/", $itemtype, $results)) { - $newrightname = 'plugin_genericobject_' . strtolower($results[1]) . 's'; - ProfileRight::deleteProfileRights([$newrightname]); - } - - $prof = new Profile(); - $profiles = getAllDataFromTable('glpi_profiles'); - foreach ($profiles as $profile) { - $helpdesk_item_types = json_decode($profile['helpdesk_item_type'], true); - if ($helpdesk_item_types !== null) { - $index = array_search($itemtype, $helpdesk_item_types); - if ($index) { - unset($helpdesk_item_types[$index]); - $tmp['id'] = $profile['id']; - $tmp['helpdesk_item_type'] = json_encode($helpdesk_item_types); - $prof->update($tmp); - } - } - } - - return true; - } else { - return false; - } - } - - // @codingStandardsIgnoreStart - public function post_deleteItem() - { - // @codingStandardsIgnoreEnd - } - - public function rawSearchOptions() - { - $sopt = []; - - $sopt[] = [ - 'id' => 'common', - 'name' => __("Objects management", "genericobject"), - ]; - - $sopt[] = [ - 'id' => 1, - 'table' => $this->getTable(), - 'field' => 'name', - 'name' => __('Model'), - 'datatype' => 'itemlink', - 'autocomplete' => true, - ]; - - $sopt[] = [ - 'id' => 5, - 'table' => $this->getTable(), - 'field' => 'is_active', - 'name' => __('Active'), - 'datatype' => 'bool', - ]; - - $sopt[] = [ - 'id' => 6, - 'table' => $this->getTable(), - 'field' => 'use_tickets', - 'name' => __('Associable to a ticket'), - 'datatype' => 'bool', - ]; - - $sopt[] = [ - 'id' => 9, - 'table' => $this->getTable(), - 'field' => 'use_history', - 'name' => _sx('button', 'Use') . ' ' . __('Historical'), - 'datatype' => 'bool', - ]; - - $sopt[] = [ - 'id' => 13, - 'table' => $this->getTable(), - 'field' => 'use_infocoms', - 'name' => _sx('button', 'Use') . ' ' . __('Financial and administratives information'), - 'datatype' => 'bool', - ]; - - $sopt[] = [ - 'id' => 14, - 'table' => $this->getTable(), - 'field' => 'use_documents', - 'name' => _sx('button', 'Use') . ' ' . _n('Document', 'Documents', 2), - 'datatype' => 'bool', - ]; - - $sopt[] = [ - 'id' => 15, - 'table' => $this->getTable(), - 'field' => 'use_loans', - 'name' => _sx('button', 'Use') . ' ' . _n('Reservation', 'Reservations', 2), - 'datatype' => 'bool', - ]; - - $sopt[] = [ - 'id' => 16, - 'table' => $this->getTable(), - 'field' => 'use_contracts', - 'name' => _sx('button', 'Use') . ' ' . _n('Contract', 'Contracts', 2), - 'datatype' => 'bool', - ]; - - $sopt[] = [ - 'id' => 17, - 'table' => $this->getTable(), - 'field' => 'use_unicity', - 'name' => _sx('button', 'Use') . ' ' . __('Fields unicity'), - 'datatype' => 'bool', - ]; - - $sopt[] = [ - 'id' => 18, - 'table' => $this->getTable(), - 'field' => 'use_global_search', - 'name' => __('Global search'), - 'datatype' => 'bool', - ]; - - $sopt[] = [ - 'id' => 19, - 'table' => 'glpi_plugin_genericobject_typefamilies', - 'field' => 'name', - 'name' => __('Family of type of objects', 'genericobject'), - 'datatype' => 'dropdown', - ]; - - $sopt[] = [ - 'id' => 20, - 'table' => $this->getTable(), - 'field' => 'use_projects', - 'name' => _n('Project', 'Projects', 2), - 'datatype' => 'bool', - ]; - - $sopt[] = [ - 'id' => 21, - 'table' => $this->getTable(), - 'field' => 'date_mod', - 'name' => __('Last update'), - 'datatype' => 'datetime', - 'massiveaction' => false, - ]; - - $sopt[] = [ - 'id' => 22, - 'table' => $this->getTable(), - 'field' => 'use_itemdevices', - 'name' => _sx('button', 'Use') . ' ' . _n('Component', 'Components', 2), - 'datatype' => 'bool', + $query = [ + 'FROM' => getTableForItemType(self::class), + 'WHERE' => ['itemtype' => $itemtype], ]; - - $sopt[] = [ - 'id' => 121, - 'table' => $this->getTable(), - 'field' => 'date_creation', - 'name' => __('Creation date'), - 'datatype' => 'datetime', - 'massiveaction' => false, - ]; - - return $sopt; - } - - /** - * Define name of type to display in menu - * - * @return string type name - */ - public static function getMenuName() - { - return __('Objects management', 'genericobject'); - } - - //------------------------------------- End Framework hooks ----------------------------- - - //------------------------------------- Forms ------------------------------------------- - public function showForm($ID, $options = []) - { - - if ($ID > 0) { - $this->check($ID, READ); - } else { - // Create item - $this->check(-1, CREATE); - $this->getEmpty(); - } - - $this->initForm($ID); - - $item = new self(); - $item->showBehaviorForm($ID); - - return true; - } - - public function showBehaviorForm($ID, $options = []) - { - /** @var array $CFG_GLPI */ - global $CFG_GLPI; - - if ($ID > 0) { - $this->check($ID, READ); - } else { - // Create item - $this->check($ID, CREATE); - $use_cache = false; - $this->getEmpty(); - } - - $this->fields['id'] = $ID; - - $right_name = PluginGenericobjectProfile::getProfileNameForItemtype( - __CLASS__ - ); - - $canedit = Session::haveRight($right_name, UPDATE); - - self::includeLocales($this->fields["name"]); - self::includeConstants($this->fields["name"]); - - $this->showFormHeader($options); - - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - echo ""; - - echo ""; - echo ""; - echo ""; - - if (!$this->isNewID($ID)) { - $canedit = $this->can($ID, CREATE); - echo ""; - - $use = [ - "use_recursivity" => __("Child entities"), - "use_tickets" => __("Assistance"), - "use_deleted" => __("Item in the dustbin"), - "use_notepad" => _n('Note', 'Notes', 2), - "use_history" => __("Historical"), - "use_template" => __("Templates"), - "use_infocoms" => __("Financial and administratives information"), - "use_contracts" => _n("Contract", "Contracts", 2), - "use_documents" => _n("Document", "Documents", 2), - "use_loans" => _n("Reservation", "Reservations", 2), - // Disable unicity feature; see #16 - // Related code : search for #16 - "use_unicity" => __("Fields unicity"), - "use_global_search" => __("Global search"), - "use_projects" => _n("Project", "Projects", 2), - "use_network_ports" => __("Network connections", "genericobject"), - "use_itemdevices" => _n('Component', 'Components', 2), - "use_impact" => Impact::getTypeName(), - ]; - - $plugins = [ - "use_plugin_datainjection" => __("injection file plugin", "genericobject"), - //"use_plugin_pdf" => __("PDF plugin", "genericobject"), - "use_plugin_geninventorynumber" => __("geninventorynumber plugin", "genericobject"), - "use_plugin_order" => __("order plugin", "genericobject"), - "use_plugin_uninstall" => __("item's uninstallation plugin", "genericobject"), - "use_plugin_simcard" => __("simcard plugin", "genericobject"), - "use_plugin_treeview" => __("treeview plugin", "genericobject"), - ]; - - $plugin = new Plugin(); - $odd = 0; - foreach ($use as $right => $label) { - if (!$odd) { - echo ""; - } - echo ""; - echo ""; - if ($odd == 1) { - $odd = 0; - echo ""; - } else { - $odd++; - } - } - if ($odd != 0) { - echo ""; + $result = $DB->request($query); + if ($result->numrows() > 0) { + foreach ($result as $field) { + $this->fields = $field; } - - echo ""; - - echo ''; - echo ""; - echo ''; - - echo ''; - echo ""; - echo ""; - echo ''; - - echo ""; - $odd = 0; - foreach ($plugins as $right => $label) { - if (!$odd) { - echo ""; - } - echo ""; - echo ""; - if ($odd == 1) { - $odd = 0; - echo ""; - } else { - $odd++; - } - } - if ($odd != 0) { - echo ""; - } - } - - $this->showFormButtons($options); - } - - /** - * - * Show a form with a button to regenerate all files - * @since 2.2.0 - * @param $ID type ID - * @return void - */ - public function showFilesForm() - { - echo ""; - echo "
"; - echo "
" . __("Internal identifier", "genericobject") . ""; - if (!$ID) { - echo Html::input( - 'name', - [ - 'value' => $this->fields['name'], - ] - ); - } else { - echo ""; - echo $this->fields["name"]; - } - - echo "
" . __("Label") . ""; - if ($ID) { - $itemtype = $this->fields["itemtype"]; - echo $itemtype::getTypeName(); - } - echo "" . __("Comments") . " :
" . __("Active") . ""; - if (!$ID) { - echo __("No"); - } else { - Dropdown::showYesNo("is_active", $this->fields["is_active"]); - } - echo "
" . __("Family of type of objects", 'genericobject') . ""; - PluginGenericobjectTypeFamily::dropdown([ - 'value' => $this->fields["plugin_genericobject_typefamilies_id"] - ]); - echo "
"; - echo __("Behaviour", "genericobject"); - echo "
" . _sx('button', 'Use') . " " . $label . ""; - - switch ($right) { - case 'use_deleted': - Html::showCheckbox(['name' => $right, - 'checked' => $this->canBeDeleted() - ]); - break; - - case 'use_recursivity': - Html::showCheckbox(['name' => $right, - 'value' => $this->canBeRecursive(), - 'checked' => $this->canBeRecursive() - ]); - break; - - case 'use_notes': - Html::showCheckbox(['name' => $right, - 'checked' => $this->canUseNotepad() - ]); - break; - - case 'use_template': - Html::showCheckbox(['name' => $right, - 'checked' => $this->canUseTemplate() - ]); - break; - - case 'use_impact': - Html::showCheckbox([ - 'name' => $right, - 'checked' => Impact::isEnabled($this->fields['itemtype']) - ]); - break; - - default: - Html::showCheckbox(['name' => $right, - 'checked' => $this->fields[$right] - ]); - break; - } - echo "
"; - echo __("Icon (impact analysis)", "genericobject"); - echo "
"; - $src = $this->getImpactIconUrl() ?? $CFG_GLPI["root_doc"] . "/pics/impact/default.png"; - echo ""; - echo "
"; - echo Html::file([ - 'name' => "impact_icon", - 'onlyimages' => true, - ]); - echo "
"; - echo _n("Plugin", "Plugins", 2); - echo "
" . _sx('button', 'Use') . " " . $label . ""; - switch ($right) { - case 'use_plugin_datainjection': - if ($plugin->isActivated('datainjection')) { - Html::showCheckbox(['name' => $right, - 'checked' => $this->fields[$right] - ]); - } else { - echo Dropdown::EMPTY_VALUE; - echo "\n"; - } - break; - - case 'use_plugin_pdf': - if ($plugin->isActivated('pdf')) { - Html::showCheckbox(['name' => $right, - 'checked' => $this->fields[$right] - ]); - } else { - echo Dropdown::EMPTY_VALUE; - echo "\n"; - } - break; - - case 'use_plugin_order': - if ($plugin->isActivated('order')) { - Html::showCheckbox(['name' => $right, - 'checked' => $this->fields[$right] - ]); - } else { - echo Dropdown::EMPTY_VALUE; - echo "\n"; - } - break; - - case 'use_plugin_uninstall': - if ($plugin->isActivated('uninstall')) { - Html::showCheckbox(['name' => $right, - 'checked' => $this->fields[$right] - ]); - } else { - echo Dropdown::EMPTY_VALUE; - echo "\n"; - } - break; - - case 'use_plugin_simcard': - if ($plugin->isActivated('simcard')) { - Html::showCheckbox(['name' => $right, - 'checked' => $this->fields[$right] - ]); - } else { - echo Dropdown::EMPTY_VALUE; - echo "\n"; - } - break; - case 'use_plugin_treeview': - if ($plugin->isActivated('treeview')) { - Html::showCheckbox(['name' => $right, - 'checked' => $this->fields[$right] - ]); - } else { - echo Dropdown::EMPTY_VALUE; - echo "\n"; - } - - break; - case 'use_plugin_geninventorynumber': - if ($plugin->isActivated('geninventorynumber')) { - Html::showCheckbox(['name' => $right, - 'checked' => $this->fields[$right] - ]); - } else { - echo Dropdown::EMPTY_VALUE; - echo "\n"; - } - break; - } - echo "
"; - echo ""; - echo "
"; - echo ""; - echo ""; - echo "
"; - Html::closeForm(); - } - - public function showLinkedTypesForm() - { - /** @var array $GO_LINKED_TYPES */ - global $GO_LINKED_TYPES; - - $this->showFormHeader(); - echo ""; - echo "
"; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - $this->showFormButtons(['candel' => false, 'canadd' => false]); - Html::closeForm(); - } - //------------------------------------- End Forms -------------------------------------- - - /** - * Create an object, it's table, files and rights - * - * @since 2.1.5 - * @param string $name object short name - * @param string $itemtype object class name - * @param array $options create options : - * - add_table : add the object table (default is no) - * - create_default_profile : add default right (default is no) for current user profile - * - add_injection_file : add file to integrate itemtype into the datainjection plugin - * - add_language_file : create a default language for the itemtype - * @return void - */ - public static function addNewObject($name, $itemtype, $options = []) - { - $params['add_table'] = false; - $params['create_default_profile'] = false; - $params['add_injection_file'] = false; - $params['add_language_file'] = true; - $params['overwrite_locales'] = false; - - foreach ($options as $key => $value) { - $params[$key] = $value; - } - - if ($params['add_table']) { - self::addTable($itemtype); - } - - //Write object class on the filesystem - self::addClassFile($name, $itemtype); - - //Write the form on the filesystem - self::addFormFile($name, $itemtype); - self::addSearchFile($name, $itemtype); - - if ($params['overwrite_locales']) { - //Add language file - self::addLocales($name, $itemtype); - } - - //Add file needed by datainjectin plugin - if ($params['add_injection_file']) { - self::addDatainjectionFile($name); - } - PluginGenericobjectProfile::installRights(); - if ($params['create_default_profile']) { - //Create rights for this new object - PluginGenericobjectProfile::createAccess($_SESSION["glpiactiveprofile"]["id"], $itemtype, true); - //Reload profiles - PluginGenericobjectProfile::changeProfile(); - } - } - - /** - * - * Add a new dropdown :class & files - * @param string $name - * @param string $itemtype - * @param array $options - */ - public static function addNewDropdown($name, $itemtype, $options = []) - { - $params['entities_id'] = false; - $params['is_recursive'] = false; - $params['is_tree'] = false; - $params['linked_itemtype'] = false; - foreach ($options as $key => $value) { - $params[$key] = $value; - } - //Add files on the disk - self::addDropdownClassFile($name, $itemtype, $params); - self::addDropdownTable(getTableForItemType($itemtype), $params); - self::addDropdownFrontFile($name); - self::addDropdownFrontformFile($name); - - // Invalidate submenu data in current session - unset($_SESSION['glpimenu']); - } - - /** - * - * Add or delete, if needed some fields to make sure that the itemtype is compatible with - * GLPI framework - */ - public function checkNecessaryFieldsUpdate() - { - /** @var DBmysql $DB */ - global $DB; - - $itemtype = $this->fields["itemtype"]; - $item = new $itemtype(); - $item->getEmpty(); - $table = getTableForItemType($itemtype); - - //Global search (inventory > status) - if (isset($this->input['use_global_search']) && $this->input['use_global_search']) { - PluginGenericobjectField::addNewField($table, 'serial', 'name'); - PluginGenericobjectField::addNewField($table, 'otherserial', 'serial'); - PluginGenericobjectField::addNewField($table, 'locations_id', 'otherserial'); - PluginGenericobjectField::addNewField($table, 'states_id', 'locations_id'); - PluginGenericobjectField::addNewField($table, 'users_id', 'states_id'); - PluginGenericobjectField::addNewField($table, 'groups_id', 'users_id'); - PluginGenericobjectField::addNewField($table, 'manufacturers_id', 'groups_id'); - PluginGenericobjectField::addNewField($table, 'users_id_tech', 'manufacturers_id'); - PluginGenericobjectField::addNewField($table, 'is_deleted', 'id'); - } - - if (isset($this->input['use_recursivity']) && $this->input['use_recursivity']) { - PluginGenericobjectField::addNewField($table, 'is_recursive', 'entities_id'); - } else { - PluginGenericobjectField::deleteField($table, 'is_recursive'); - } - - //Template - if (isset($this->input['use_template']) && $this->input['use_template']) { - PluginGenericobjectField::addNewField($table, 'is_template', 'id'); - PluginGenericobjectField::addNewField($table, 'template_name', 'is_template'); - } else { - PluginGenericobjectField::deleteField($table, 'is_template'); - PluginGenericobjectField::deleteField($table, 'template_name'); - } - - //Trash - if (isset($this->input['use_deleted']) && $this->input['use_deleted']) { - PluginGenericobjectField::addNewField($table, 'is_deleted', 'id'); - } else { - if (!$this->canBeReserved()) { - PluginGenericobjectField::deleteField($table, 'is_deleted'); - } else { - _log($DB->fieldExists($table, 'is_deleted')); - if ($DB->fieldExists($table, 'is_deleted')) { - Session::addMessageAfterRedirect( - __("Dustbin can't be removed since Reservations are used on this type."), - false, - WARNING - ); - } - } - } - - //Reservation needs is_deleted field ! - if ($this->canBeReserved()) { - PluginGenericobjectField::addNewField($table, 'is_deleted', 'id'); - PluginGenericobjectField::addNewField($table, 'locations_id'); - PluginGenericobjectField::addNewField($table, 'users_id'); - } - - //Helpdesk post-only - if ($this->canUseTickets()) { - //TODO rename is_helpdesk_visible into is_helpdeskvisible - PluginGenericobjectField::addNewField($table, 'is_helpdesk_visible', 'comment'); - PluginGenericobjectField::addNewField($table, 'ticket_tco'); - } else { - PluginGenericobjectField::deleteField($table, 'is_helpdesk_visible'); - } - - //Notes - if (isset($this->input['use_notepad']) && $this->input['use_notepad']) { - PluginGenericobjectField::addNewField($table, 'notepad', 'id'); - } else { - PluginGenericobjectField::deleteField($table, 'notepad'); - } - - //Networkport - if ($this->canUseNetworkPorts()) { - PluginGenericobjectField::addNewField($table, 'locations_id'); - } - - if ($this->canUseDirectConnections()) { - self::addItemsTable($itemtype); - //self::addItemClassFile($this->fields['name'], $itemtype); } else { - self::deleteItemsTable($itemtype); - self::deleteClassFile($this->fields['name'] . "_item"); - } - - if ( - $this->canUsePluginDataInjection() && - !file_exists(self::getCompleteInjectionFilename($this->fields['name'])) - ) { - self::addDatainjectionFile($this->fields['name']); - } - - if ( - !$this->canUsePluginDataInjection() && - file_exists(self::getCompleteInjectionFilename($this->fields['name'])) - ) { - self::deleteInjectionFile($this->fields['name']); - } - - //Device item needs locations_id field ! - if ($this->canUseItemDevice()) { - PluginGenericobjectField::addNewField($table, 'locations_id'); + $this->getEmpty(); } } - - /** - * Add object type table + entries in glpi_display - * @name object type's name - * @return void - */ - public static function addTable($itemtype) - { - /** @var DBmysql $DB */ - global $DB; - - $default_charset = DBConnection::getDefaultCharset(); - $default_collation = DBConnection::getDefaultCollation(); - $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); - - $query = "CREATE TABLE IF NOT EXISTS `" . getTableForItemType($itemtype) . "` ( - `id` INT {$default_key_sign} NOT NULL AUTO_INCREMENT, - `entities_id` INT {$default_key_sign} NOT NULL DEFAULT '0', - `name` VARCHAR( 255 ) NOT NULL DEFAULT '', - `comment` text, - `notepad` text, - `date_mod` TIMESTAMP NULL DEFAULT NULL, - `date_creation` TIMESTAMP NULL DEFAULT NULL, - PRIMARY KEY ( `id` ), - KEY `date_mod` (`date_mod`), - KEY `date_creation` (`date_creation`) - ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; - $DB->query($query); - - $query = "INSERT INTO `glpi_displaypreferences` (`id`, `itemtype`, `num`, `rank`, `users_id`) " . - "VALUES (NULL, '$itemtype', '2', '1', '0');"; - $DB->query($query); - } - - /** - * Add object_items table to connect an object to others - * @name object type's name - * @return void - */ - public static function addItemsTable($itemtype) - { - /** @var DBmysql $DB */ - global $DB; - - $default_charset = DBConnection::getDefaultCharset(); - $default_collation = DBConnection::getDefaultCollation(); - $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); - - $table = getTableForItemType($itemtype); - $fk = getForeignKeyFieldForTable($table); - $query = "CREATE TABLE IF NOT EXISTS `" . getTableForItemType($itemtype) . "_items` ( - `id` int {$default_key_sign} NOT NULL AUTO_INCREMENT, - `items_id` int {$default_key_sign} NOT NULL DEFAULT '0' COMMENT 'RELATION to various table, according to itemtype (ID)', - `date_mod` TIMESTAMP NULL DEFAULT NULL, - `date_creation` TIMESTAMP NULL DEFAULT NULL, - `$fk` int {$default_key_sign} NOT NULL DEFAULT '0', - `itemtype` varchar(100) NOT NULL, - PRIMARY KEY (`id`), - KEY `$fk` (`$fk`), - KEY `date_mod` (`date_mod`), - KEY `date_creation` (`date_creation`), - KEY `item` (`itemtype`,`items_id`) - ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; - $DB->query($query); - } - - - //-------------------------------- FILE CREATION / DELETION ----------------------------// + //-------------------------------- FILE DELETION ----------------------------// public static function deleteFile($filename) { if (file_exists($filename)) { @@ -1264,11 +154,11 @@ public static function getCompleteConstantFilename($name) } - /** - * Delete an used form file - * @param string $name the name of the object type - * @return void - */ + /** + * Delete an used form file + * @param string $name the name of the object type + * @return void + */ public static function deleteFormFile($name) { self::deleteFile(self::getCompleteFormFilename($name)); @@ -1287,11 +177,11 @@ public static function deleteAjaxFile($name) } - /** - * Delete an used class file - * @param string $name the name of the object type - * @return void - */ + /** + * Delete an used class file + * @param string $name the name of the object type + * @return void + */ public static function deleteClassFile($name) { self::deleteFile(self::getCompleteClassFilename($name)); @@ -1303,295 +193,23 @@ public static function deleteInjectionFile($name) self::deleteFile(self::getCompleteInjectionFilename($name)); } - - public static function addLocales($name, $itemtype) - { - /** @var array $CFG_GLPI */ - global $CFG_GLPI; - - $fsname = self::getSystemName($name); - - $locale_dir = GENERICOBJECT_LOCALES_PATH . "/" . $fsname; - if (!is_dir($locale_dir)) { - @ mkdir($locale_dir, 0755, true); - } - - $locale_files = [ - $fsname . '.' . $_SESSION['glpilanguage'], - ]; - if ($CFG_GLPI['language'] != $_SESSION['glpilanguage']) { - $locale_files[] = $fsname . '.' . $CFG_GLPI['language']; - } - - foreach ($locale_files as $locale_file) { - self::addFileFromTemplate( - [ - 'NAME' => $name, - 'CLASSNAME' => self::getClassByName($name), - ], - self::LOCALE_TEMPLATE, - $locale_dir, - $locale_file - ); - } - } - - public static function deleteLocales($name, $itemtype) { $locale_dir = GENERICOBJECT_LOCALES_PATH . "/" . self::getSystemName($name); if (file_exists($locale_dir)) { foreach (glob($locale_dir . '/*.php') as $file) { - @unlink($file); - } - @rmdir($locale_dir); - } - } - - - public static function addFileFromTemplate( - $mappings, - $template, - $directory, - $filename - ) { - if (!empty($mappings)) { - $file_read = @fopen(GENERICOBJECT_DIR . $template, "rt"); - if ($file_read) { - $template_file = fread($file_read, filesize(GENERICOBJECT_DIR . $template)); - foreach ($mappings as $name => $value) { - $template_file = str_replace("%%$name%%", $value, $template_file); - } - fclose($file_read); - $file_write = @fopen($directory . "/" . $filename . ".php", "w"); - if ($file_write) { - fwrite($file_write, $template_file); - fclose($file_write); - } - } - } - } - - - public static function addDatainjectionFile($name) - { - self::addFileFromTemplate( - ['CLASSNAME' => self::getClassByName($name), - 'INJECTIONCLASS' => self::getClassByName($name) . "Injection" - ], - self::OBJECTINJECTION_TEMPLATE, - GENERICOBJECT_CLASS_PATH, - self::getSystemName($name) . "injection.class" - ); - } - - - public static function addDropdownFrontFile($name) - { - self::addFileFromTemplate( - ['CLASSNAME' => self::getClassByName($name)], - self::FRONT_DROPDOWN_TEMPLATE, - GENERICOBJECT_FRONT_PATH, - self::getSystemName($name) - ); - } - - - public static function addAjaxFile($name, $field) - { - self::addFileFromTemplate( - ['CLASSNAME' => self::getClassByName($name)], - self::AJAX_TEMPLATE, - GENERICOBJECT_AJAX_PATH, - self::getSystemName($name) . ".tabs" - ); - } - - - public static function addDropdownFrontformFile($name) - { - self::addFileFromTemplate( - ['CLASSNAME' => self::getClassByName($name)], - self::FRONTFORM_DROPDOWN_TEMPLATE, - GENERICOBJECT_FRONT_PATH, - self::getSystemName($name) . ".form" - ); - } - - - public static function addDropdownClassFile($name, $field, $options) - { - $params['is_tree'] = false; - $params['realname'] = false; - $params['linked_itemtype'] = false; - foreach ($options as $key => $value) { - $params[$key] = $value; - } - self::addFileFromTemplate([ - 'CLASSNAME' => self::getClassByName($name), - 'EXTENDS' => - 'PluginGenericobject' . ($params['is_tree'] ? 'CommonTree' : 'Common') . 'Dropdown', - 'FIELDNAME' => $params['realname'], - 'LINKED_ITEMTYPE' => $params['linked_itemtype'] - ], self::CLASS_DROPDOWN_TEMPLATE, GENERICOBJECT_CLASS_PATH, self::getSystemName($name) . ".class"); - } - - - /** - * Write on the the class file for the new object type - * @param string $name the name of the object type - * @param string $classname the name of the new object - * @return void - */ - public static function addClassFile($name, $classname) - { - self::addFileFromTemplate( - ['CLASSNAME' => self::getClassByName($name)], - self::CLASS_TEMPLATE, - GENERICOBJECT_CLASS_PATH, - self::getSystemName($name) . ".class" - ); - } - - /** - * Write on the the _Item class file for the new object type - * @param string $name the name of the object type - * @param string $classname the name of the new object - * @return void - */ - public static function addItemClassFile($name, $classname) - { - $class = self::getClassByName($name) . "_Item"; - self::addFileFromTemplate( - ['CLASSNAME' => $class, - 'FOREIGNKEY' => getForeignKeyFieldForItemType($classname), - 'SOURCEOBJECT' => $classname - ], - self::OBJECTITEM_TEMPLATE, - GENERICOBJECT_CLASS_PATH, - self::getSystemName($name) . "_item.class" - ); - } - - /** - * Write on the the form file for the new object type - * @param string $name the name of the object type - * @param string $classname the name of the new object - * @return void - */ - public static function addFormFile($name, $classname) - { - self::addFileFromTemplate( - ['CLASSNAME' => self::getClassByName($name)], - self::FORM_TEMPLATE, - GENERICOBJECT_FRONT_PATH, - self::getSystemName($name) . ".form" - ); - } - - - /** - * Write on the the form file for the new object type - * @param string $name the name of the object type - * @param string $classname the name of the new object - * @return void - */ - public static function addSearchFile($name, $classname) - { - self::addFileFromTemplate( - ['CLASSNAME' => self::getClassByName($name)], - self::SEARCH_TEMPLATE, - GENERICOBJECT_FRONT_PATH, - self::getSystemName($name) - ); - } - - - /** - * Create, if needed files for an itemtype and it's dropdown - * - * @since 2.2.0 - * - * @return void - */ - public static function checkClassAndFilesForItemType() - { - foreach (self::getTypes(true) as $type) { - //ensure old files has been removed, - $fsname = self::getSystemName($type['name']); - if (file_exists(GENERICOBJECT_DIR . "/inc/{$fsname}.class.php")) { - unlink(GENERICOBJECT_DIR . "/inc/{$fsname}.class.php"); - } - if (file_exists(GENERICOBJECT_DIR . "/front/{$fsname}.form.php")) { - unlink(GENERICOBJECT_DIR . "/front/{$fsname}.form.php"); - } - if (file_exists(GENERICOBJECT_DIR . "/front/{$fsname}.php")) { - unlink(GENERICOBJECT_DIR . "/front/{$fsname}.form.php"); - } - if (file_exists(GENERICOBJECT_DIR . "/ajax/{$fsname}.tabs.php")) { - unlink(GENERICOBJECT_DIR . "/ajax/{$fsname}.tabs.php"); - } - if (file_exists(GENERICOBJECT_DIR . "/inc/{$fsname}.injection.class.php")) { - unlink(GENERICOBJECT_DIR . "/inc/{$fsname}.injection.class.php"); - } - - self::checkClassAndFilesForOneItemType($type['itemtype'], $type['name'], true, false); - } - } - - /** - * - * Create or overwrite files for an itemtype - * @since 2.2.0 - * @param string $itemtype the itemtype to check - * @param string $name type's short name - * @param boolean $overwrite force to overwrite existing files - * @param boolean $overwrite_locales force to overwrite existing locales - * @return void - */ - public static function checkClassAndFilesForOneItemType($itemtype, $name, $overwrite = false, $overwrite_locales = true) - { - /** @var DBmysql $DB */ - global $DB; - $table = getTableForItemType($itemtype); - - //If class doesn't exist but table exists, create class - if ($DB->tableExists($table) && ($overwrite || !class_exists($itemtype))) { - self::addNewObject($name, $itemtype, ['add_table' => false, - 'create_default_profile' => false, - 'add_injection_file' => $overwrite, - 'add_language_file' => false, - 'overwrite_locales' => $overwrite_locales - ]); - } - - foreach ($DB->listFields($table) as $field => $options) { - if (preg_match("/s_id$/", $field)) { - $dropdowntable = getTableNameForForeignKeyField($field); - $dropdownclass = getItemTypeForTable($dropdowntable); - - if ($DB->tableExists($dropdowntable) && ! class_exists($dropdownclass)) { - $name = str_replace("glpi_plugin_genericobject_", "", $dropdowntable); - $name = getSingular($name); - $params = PluginGenericobjectField::getFieldOptions($field, $dropdownclass); - if ( - isset($params['dropdown_type']) - and $params['dropdown_type'] === 'isolated' - ) { - $params['linked_itemtype'] = $itemtype; - } - self::addNewDropdown($name, self::getClassByName($name), $params); - } + @unlink($file); } + @rmdir($locale_dir); } } - /** - * - * Delete all files and classes for an itemtype (including dropdowns) - * @since 2.2.0 - * @param string $name file name - */ + /** + * + * Delete all files and classes for an itemtype (including dropdowns) + * @since 2.2.0 + * @param string $name file name + */ public static function deleteItemTypeFilesAndClasses($name, $table, $itemtype) { /** @var DBmysql $DB */ @@ -1603,52 +221,52 @@ public static function deleteItemTypeFilesAndClasses($name, $table, $itemtype) "itemtype" => $itemtype, ]); - //Delete files related to dropdowns + //Delete files related to dropdowns foreach ($DB->listFields($table) as $field => $options) { if (preg_match("/plugin_genericobject_(.*)_id/", $field, $results)) { $table = getTableNameForForeignKeyField($field); if ($table != getTableForItemType("PluginGenericobjectTypeFamily")) { self::deleteFilesAndClassesForOneItemtype(getSingular($results[1])); - $DB->query("DROP TABLE IF EXISTS `$table`"); + $DB->dropTable($table, true); } } } - //Delete reference in various GLPI core tables + //Delete reference in various GLPI core tables self::deleteItemtypeReferencesInGLPI($itemtype); - //Delete itemtype files + //Delete itemtype files self::deleteFilesAndClassesForOneItemtype($name); - //Drop itemtype table + //Drop itemtype table self::deleteItemsTable($itemtype); self::deleteTable($itemtype); } - /** - * Delete all files for an itemtype - * - * @since 2.2.0 - * @param string $name class file name - */ + /** + * Delete all files for an itemtype + * + * @since 2.2.0 + * @param string $name class file name + */ public static function deleteFilesAndClassesForOneItemtype($name) { - //This is for compatibility with older versions of GLPI - //(where ajax files were used for tabs display, which is not the case anymore with GLPI 0.83+) + //This is for compatibility with older versions of GLPI + //(where ajax files were used for tabs display, which is not the case anymore with GLPI 0.83+) self::deleteAjaxFile($name); - //Delete itemtype class + //Delete itemtype class self::deleteClassFile($name); - //Delete forms + //Delete forms self::deleteSearchFile($name); self::deleteFormFile($name); - //Delete datainjection compatiblity file + //Delete datainjection compatiblity file self::deleteInjectionFile($name); } public static function deleteItemtypeReferencesInGLPI($itemtype) { - //Delete references to PluginGenericobjectType in the following tables + //Delete references to PluginGenericobjectType in the following tables $itemtypes = ["Contract_Item", "DisplayPreference", "Document_Item", "SavedSearch", "Log"]; foreach ($itemtypes as $type) { $item = new $type(); @@ -1656,70 +274,13 @@ public static function deleteItemtypeReferencesInGLPI($itemtype) } } - //-------------------- ADD / DELETE TABLES ----------------------------------// - - /** - * Add a new dropdown table - * @param string $table the table name - * @param array $options - * @return void - */ - public static function addDropdownTable($table, $options = []) - { - /** @var DBmysql $DB */ - global $DB; - - $default_charset = DBConnection::getDefaultCharset(); - $default_collation = DBConnection::getDefaultCollation(); - $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); - - $params['entities_id'] = false; - $params['is_recursive'] = false; - $params['is_tree'] = false; - foreach ($options as $key => $value) { - $params[$key] = $value; - } - - if (!$DB->tableExists($table)) { - $query = "CREATE TABLE IF NOT EXISTS `$table` ( - `id` int {$default_key_sign} NOT NULL auto_increment, - `name` varchar(255) default NULL, - `comment` text, - `date_mod` TIMESTAMP NULL DEFAULT NULL, - `date_creation` TIMESTAMP NOT NULL, - PRIMARY KEY (`id`), - KEY `date_mod` (`date_mod`), - KEY `date_creation` (`date_creation`), - KEY `name` (`name`) - ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; - $DB->query($query); - } - if ($params['entities_id']) { - $query = "ALTER TABLE `$table` ADD `entities_id` INT {$default_key_sign} NOT NULL DEFAULT '0'"; - $DB->query($query); - if ($params['is_recursive']) { - $query = "ALTER TABLE `$table` " . - "ADD `is_recursive` TINYINT NOT NULL DEFAULT '0' AFTER `entities_id`"; - $DB->query($query); - } - } - if ($params['is_tree']) { - $fk = getForeignKeyFieldForTable($table); - $query = "ALTER TABLE `$table` ADD `completename` text, - ADD `$fk` int {$default_key_sign} NOT NULL DEFAULT '0', - ADD `level` int NOT NULL DEFAULT '0', - ADD `ancestors_cache` longtext, - ADD `sons_cache` longtext"; - $DB->query($query); - } - } - + //-------------------- ADD / DELETE TABLES ----------------------------------// - /** - * Delete object type table + entries in glpi_display - * @name string $itemtype object type's name - * @return void - */ + /** + * Delete object type table + entries in glpi_display + * @name string $itemtype object type's name + * @return void + */ public static function deleteTable($itemtype) { /** @var DBmysql $DB */ @@ -1727,47 +288,27 @@ public static function deleteTable($itemtype) _log($itemtype); $preferences = new DisplayPreference(); $preferences->deleteByCriteria(["itemtype" => $itemtype]); - $DB->query("DROP TABLE IF EXISTS `" . getTableForItemType($itemtype) . "`"); + $DB->dropTable(getTableForItemType($itemtype), true); } - /** - * Delete object _items table - * @name string $itemtype object type's name - * @return void - */ + /** + * Delete object _items table + * @name string $itemtype object type's name + * @return void + */ public static function deleteItemsTable($itemtype) { /** @var DBmysql $DB */ global $DB; - $DB->query("DROP TABLE IF EXISTS `" . getTableForItemType($itemtype) . "_items`"); - } - - /** - * Get object name by ID - * @param string $itemtype - * @return string the name associated with the ID - */ - public static function getNameByID($itemtype) - { - /** @var DBmysql $DB */ - global $DB; - $query = "SELECT `name` FROM `" . getTableForItemType(__CLASS__) . "` " . - "WHERE `itemtype`='$itemtype'"; - $result = $DB->query($query); - if ($DB->numrows($result)) { - return $DB->result($result, 0, "name"); - } else { - return ""; - } + $DB->dropTable(getTableForItemType($itemtype) . "_items", true); } - - /** - * Delete all tickets for an itemtype - * @param string $itemtype - * @return void - */ + /** + * Delete all tickets for an itemtype + * @param string $itemtype + * @return void + */ public static function deleteTicketAssignation($itemtype) { $types = ['Item_Ticket', 'Item_Problem', 'Change_Item']; @@ -1777,11 +318,11 @@ public static function deleteTicketAssignation($itemtype) } } - /** - * Delete all simcards for an itemtype - * @param string $itemtype - * @return void - */ + /** + * Delete all simcards for an itemtype + * @param string $itemtype + * @return void + */ public static function deleteSimcardAssignation($itemtype) { $plugin = new Plugin(); @@ -1791,23 +332,23 @@ public static function deleteSimcardAssignation($itemtype) //@phpstan-ignore-next-line $item = new $type(); $item->deleteByCriteria([ - 'itemtype' => $itemtype + 'itemtype' => $itemtype, ]); } } } - /** - * Remove datainjection models for an itemtype - * @param string $itemtype - * @return void - */ + /** + * Remove datainjection models for an itemtype + * @param string $itemtype + * @return void + */ public static function removeDataInjectionModels($itemtype) { - //Delete if exists datainjection models - if (Plugin::isPluginActive("datainjection")) { - //@phpstan-ignore-next-line - $model = new PluginDatainjectionModel(); + //Delete if exists datainjection models + if (Plugin::isPluginActive("datainjection") && class_exists('PluginDatainjectionModel')) { + /** @var CommonDBTM $model */ + $model = new PluginDatainjectionModel(); // @phpstan-ignore-line foreach ($model->find(['itemtype' => $itemtype]) as $data) { $model->delete($data); } @@ -1815,11 +356,11 @@ public static function removeDataInjectionModels($itemtype) } - /** - * Delete all loans associated with a itemtype - * @param string $itemtype - * @return void - */ + /** + * Delete all loans associated with a itemtype + * @param string $itemtype + * @return void + */ public static function deleteLoans($itemtype) { $reservation_item = new ReservationItem(); @@ -1829,11 +370,11 @@ public static function deleteLoans($itemtype) } - /** - * Delete all loans associated with a itemtype - * @param string $itemtype - * @return void - */ + /** + * Delete all loans associated with a itemtype + * @param string $itemtype + * @return void + */ public static function deleteUnicity($itemtype) { $unicity = new FieldUnicity(); @@ -1841,11 +382,11 @@ public static function deleteUnicity($itemtype) } - /** - * Delete all notes associated with a itemtype - * @param string $itemtype - * @return void - */ + /** + * Delete all notes associated with a itemtype + * @param string $itemtype + * @return void + */ public static function deleteNotepad($itemtype) { $notepad = new Notepad(); @@ -1853,11 +394,11 @@ public static function deleteNotepad($itemtype) } - /** - * Delete network ports for an itemtype - * @param string $itemtype - * @return void - */ + /** + * Delete network ports for an itemtype + * @param string $itemtype + * @return void + */ public static function deleteNetworking($itemtype) { $networkport = new NetworkPort(); @@ -1866,44 +407,43 @@ public static function deleteNetworking($itemtype) } } - /** - * Delete reservations for an itemtype - * @param string $itemtype - * @return void - */ + /** + * Delete reservations for an itemtype + * @param string $itemtype + * @return void + */ public static function deleteReservations($itemtype) { /** @var DBmysql $DB */ global $DB; - - $query = "DELETE FROM - `glpi_reservations` - WHERE `reservationitems_id` in ( - SELECT `id` from `glpi_reservationitems` WHERE `itemtype`='$itemtype' - )"; - $DB->query($query); + $reservation = new Reservation(); + $reservation_item = new ReservationItem(); + $reservation_items = $reservation_item->find(['itemtype' => $itemtype]); + foreach ($reservation_items as $data) { + $reservation->deleteByCriteria(['reservationitems_id' => $data['id']]); + } } - /** - * Delete reservations for an itemtype - * @param string $itemtype - * @return void - */ + /** + * Delete reservations for an itemtype + * @param string $itemtype + * @return void + */ public static function deleteReservationItems($itemtype) { $reservationItem = new ReservationItem(); $reservationItem->deleteByCriteria(['itemtype' => $itemtype], true); } - /** - * Filter values inserted by users : remove accented chars - * @param string $value the value to be filtered - * @return string the filtered value - */ + /** + * Filter values inserted by users : remove accented chars + * @param string $value the value to be filtered + * @return string the filtered value + */ public static function filterInput($value) { $value = strtolower($value); - //Itemtype must always be singular, otherwise it breaks when using GLPI's framework + //Itemtype must always be singular, otherwise it breaks when using GLPI's framework $value = getSingular($value); $search = explode(",", "ç,æ,œ,á,é,í,ó,ú,à,è,ì,ò,ù,ä,ë,ï,ö,ü,ÿ,â,ê,î,ô,û,å,e,i,ø,u"); @@ -1915,65 +455,44 @@ public static function filterInput($value) } - /** - * Get the object system name (for files and itemtype), by giving the name - * - * @param string $name - * - * @return string - */ + /** + * Get the object system name (for files and itemtype), by giving the name + * + * @param string $name + * + * @return string + */ public static function getSystemName($name) { - // Force filtering of name (will have no effect if already done). + // Force filtering of name (will have no effect if already done). $name = self::filterInput($name); - // Replace numbers by letters + // Replace numbers by letters return str_replace( ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'], - $name + $name, ); } - /** - * Get the object class, by giving the name - * @param string $name the object's internal identifier - * @return string the class associated with the object - */ + /** + * Get the object class, by giving the name + * @param string $name the object's internal identifier + * @return string the class associated with the object + */ public static function getClassByName($name) { return 'PluginGenericobject' . ucfirst(self::getSystemName($name)); } - - public static function getFamilyNameByItemtype($itemtype) - { - $types = getAllDataFromTable( - "glpi_plugin_genericobject_types", - ['itemtype' => $itemtype, 'is_active' => 1] - ); - if (empty($types)) { - return false; - } else { - $type = array_pop($types); - if ($type['plugin_genericobject_typefamilies_id'] > 0) { - $family = new PluginGenericobjectTypeFamily(); - $family->getFromDB($type['plugin_genericobject_typefamilies_id']); - return $family->getName(); - } else { - return false; - } - } - } - - /** - * Get all types of active&published objects - */ + /** + * Get all types of active&published objects + */ public static function getTypes($all = false) { /** @var DBmysql $DB */ global $DB; - $table = getTableForItemType(__CLASS__); + $table = getTableForItemType(self::class); if ($DB->tableExists($table)) { $mytypes = []; $all_types = getAllDataFromTable( @@ -1981,34 +500,11 @@ public static function getTypes($all = false) [ 'WHERE' => !$all ? ['is_active' => self::ACTIVE] : [], 'ORDER' => 'name', - ] + ], ); foreach ($all_types as $data) { - //If class is not present on the filesystem, do not list itemtype - $mytypes[$data['itemtype']] = $data; - } - return $mytypes; - } else { - return []; - } - } - - /** - * Get all types of active&published objects - * order by family - */ - public static function getTypesByFamily($all = false) - { - /** @var DBmysql $DB */ - global $DB; - $table = getTableForItemType(__CLASS__); - if ($DB->tableExists($table)) { - $mytypes = []; - foreach (getAllDataFromTable($table, (!$all ? ['is_active' => self::ACTIVE] : [])) as $data) { //If class is not present on the filesystem, do not list itemtype - if (file_exists(self::getCompleteClassFilename($data['name']))) { - $mytypes[$data['plugin_genericobject_typefamilies_id']][$data['itemtype']] = $data; - } + $mytypes[$data['itemtype']] = $data; } return $mytypes; } else { @@ -2016,344 +512,7 @@ public static function getTypesByFamily($all = false) } } - public static function getTypesForFormcreator($param) - { - $families = PluginGenericobjectTypeFamily::getFamilies(); - $familyFk = PluginGenericobjectTypeFamily::getForeignKeyField(); - foreach (self::getTypes() as $type => $typeData) { - $familyName = isset($families[$typeData[$familyFk]]) - ? $families[$typeData[$familyFk]] - : _n('Other', 'Others', Session::getPluralNumber(), 'genericobject'); - $param[$familyName][$type] = $typeData['name']; - } - return $param; - } - - /** - * Register all variables for a type - * @param string $itemtype the type's attributes - * @return void - */ - public static function registerOneType($itemtype) - { - //If table doesn't exists, do not try to register ! - if (class_exists($itemtype)) { - $itemtype::registerType(); - } - } - - - /** - * Include locales for a specific type - * @name object type's name - * @return void - */ - public static function includeLocales($name) - { - /** @var array $CFG_GLPI */ - global $CFG_GLPI; - - $fsname = self::getSystemName($name); - - $prefix = GENERICOBJECT_LOCALES_PATH . "/$fsname/$fsname"; - //Dirty hack because the plugin doesn't support gettext... - $language = str_replace('.mo', '', $CFG_GLPI["languages"][$_SESSION["glpilanguage"]][1]); - if ( - isset($_SESSION["glpilanguage"]) - && file_exists("$prefix.$language.php") - ) { - include_once("$prefix.$language.php"); - } else { - if (file_exists($prefix . ".en_GB.php")) { - include_once($prefix . ".en_GB.php"); - } else { - if (file_exists($prefix . ".fr_FR.php")) { - include_once($prefix . ".fr_FR.php"); - } else { - return false; - } - } - } - return true; - } - - - public static function includeConstants($name, $force = false) - { - - $file = self::getCompleteConstantFilename($name); - if (file_exists($file)) { - if (!$force) { - include_once($file); - } else { - include($file); - } - } - } - - - /** - * Get all dropdown fields associated with an itemtype - * @param string $itemtype the itemtype - * @return array or fields that represents the dropdown tables - */ - public static function getDropdownForItemtype($itemtype) - { - $associated_tables = []; - if (class_exists($itemtype)) { - $source_table = getTableForItemType($itemtype); - foreach (PluginGenericobjectSingletonObjectField::getInstance($itemtype) as $field => $value) { - $table = getTableNameForForeignKeyField($field); - $options = PluginGenericobjectField::getFieldOptions($field, $itemtype); - if ( - isset($options['input_type']) - and $options['input_type'] === 'dropdown' - and preg_match('/^glpi_plugin_genericobject/', $table) - ) { - $associated_tables[] = $table; - } - } - } - return $associated_tables; - } - - - public static function deleteDropdownsForItemtype($itemtype) - { - /** @var DBmysql $DB */ - global $DB; - //Foreach dropdown : drop table & remove files ! - foreach (self::getDropdownForItemtype($itemtype) as $table) { - $results = []; - if ( - preg_match("/glpi_plugin_genericobject_(.*)/i", getSingular($table), $results) - && isset($results[1]) - ) { - $name = $results[1]; - $DB->query("DROP TABLE IF EXISTS `$table`"); - self::deleteFormFile($name); - self::deleteSearchFile($name); - self::deleteClassFile($name); - } - } - - // Invalidate submenu data in current session for minor cleanup - unset($_SESSION['glpimenu']); - } - //------------------------------- GETTERS -------------------------// - - public function canUseTickets() - { - return $this->fields['use_tickets']; - } - - public function canBeLinked() - { - return $this->fields['use_links']; - } - - public function canUseTemplate() - { - /** @var DBmysql $DB */ - global $DB; - return $DB->fieldExists(getTableForItemType($this->fields['itemtype']), 'is_template'); - } - - - public function canUseUnicity() - { - return $this->fields['use_unicity']; - } - - - public function canBeDeleted() - { - /** @var DBmysql $DB */ - global $DB; - return $DB->fieldExists(getTableForItemType($this->fields['itemtype']), 'is_deleted'); - } - - - public function canBeEntityAssigned() - { - /** @var DBmysql $DB */ - global $DB; - return $DB->fieldExists(getTableForItemType($this->fields['itemtype']), 'entities_id'); - } - - - public function canBeRecursive() - { - /** @var DBmysql $DB */ - global $DB; - return $DB->fieldExists(getTableForItemType($this->fields['itemtype']), 'is_recursive'); - } - - - public function canBeReserved() - { - return $this->fields['use_loans']; - } - - - public function canUseNotepad() - { - return $this->fields['use_notepad'] != 0; - } - - - public function canUseHistory() - { - return $this->fields['use_history']; - } - - - public function canUseDocuments() - { - return $this->fields['use_documents']; - } - - - public function canUseInfocoms() - { - return $this->fields['use_infocoms']; - } - - public function canUseItemDevice() - { - return $this->fields['use_itemdevices']; - } - - public function canUseImpact() - { - return Impact::isEnabled($this->fields['itemtype']); - } - - public function canUseContracts() - { - return $this->fields['use_contracts']; - } - - - public function canUseGlobalSearch() - { - return $this->fields['use_global_search']; - } - - - public function canUseNetworkPorts() - { - return $this->fields['use_network_ports']; - } - - - public function canUseDirectConnections() - { - return $this->fields['use_direct_connections']; - } - - public function canUseProjects() - { - return $this->fields['use_projects']; - } - - public function canUsePluginDataInjection() - { - if (!Plugin::isPluginActive("datainjection")) { - return false; - } - return $this->fields['use_plugin_datainjection']; - } - - - public function canUsePluginOrder() - { - if (!Plugin::isPluginActive("order")) { - return false; - } - return $this->fields['use_plugin_order']; - } - - - public function canUsePluginPDF() - { - if (!Plugin::isPluginActive("pdf")) { - return false; - } - return $this->fields['use_plugin_pdf']; - } - - - public function canUsePluginUninstall() - { - if (!Plugin::isPluginActive("uninstall")) { - return false; - } - return $this->fields['use_plugin_uninstall']; - } - - public function canUsePluginSimcard() - { - if (!Plugin::isPluginActive("simcard")) { - return false; - } - return $this->fields['use_plugin_simcard']; - } - - public function canUsePluginTreeview() - { - if (!Plugin::isPluginActive("treeview")) { - return false; - } - return $this->fields['use_plugin_treeview']; - } - - public function canUsePluginGeninventoryNumber() - { - if (!Plugin::isPluginActive("geninventorynumber")) { - return false; - } - return $this->fields['use_plugin_geninventorynumber']; - } - - - public function isTransferable() - { - return Session::isMultiEntitiesMode(); - } - - public function getLinkedItemTypesAsArray() - { - if (!empty($this->fields['linked_itemtypes'])) { - return json_decode($this->fields['linked_itemtypes'], true); - } else { - return []; - } - } - - public static function canViewAtLeastOneType() - { - $types = self::getTypes(); - $view = false; - foreach ($types as $ID => $value) { - if (Session::haveRight($value['itemtype'], READ)) { - $view = true; - break; - } - } - return $view; - } - - /** - * Display debug information for current object - **/ - public function showDebug() - { - $this->showFilesForm(); - //NotificationEvent::debugEvent($this); - } - //------------------------------- INSTALL / UNINSTALL METHODS -------------------------// - + //------------------------------- INSTALL / UNINSTALL METHODS -------------------------// public static function install(Migration $migration) { @@ -2364,7 +523,7 @@ public static function install(Migration $migration) $default_collation = DBConnection::getDefaultCollation(); $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); - $table = getTableForItemType(__CLASS__); + $table = getTableForItemType(self::class); if (!$DB->tableExists($table)) { $query = "CREATE TABLE `$table` ( `id` INT {$default_key_sign} NOT NULL AUTO_INCREMENT, @@ -2399,7 +558,7 @@ public static function install(Migration $migration) `impact_icon` varchar(255) default NULL, PRIMARY KEY ( `id` ) ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; - $DB->query($query) or die($DB->error()); + $DB->doQuery($query); } $migration->addField($table, "use_network_ports", "bool"); @@ -2423,26 +582,19 @@ public static function install(Migration $migration) $migration->addField($table, "impact_icon", "string"); $migration->migrationOneTable($table); - //Normalize names and itemtypes (prior to using them). + //Normalize names and itemtypes (prior to using them). self::normalizeNamesAndItemtypes($migration); - //If files are missing, recreate them! - self::checkClassAndFilesForItemType(); - - // Migrate notepad data + // Migrate notepad data $allGenericObjectTypes = PluginGenericobjectType::getTypes(true); $notepad = new Notepad(); foreach ($allGenericObjectTypes as $genericObjectType => $genericObjectData) { - $itemtype = $genericObjectData['itemtype']; - if (! class_exists($itemtype, true)) { - // TRANS: %1$s is itemtype name - $warning = sprintf(__('Unable to load the class %1$s.', 'genericobject'), $itemtype); - // TRANS: %1$s is itemtype name - $warning .= sprintf(__('You probably have garbage data in your database for this plugin and missing files in %1$s', 'genericobject'), GENERICOBJECT_DOC_DIR); - $migration->displayWarning($warning, true); - die(); + if (!class_exists($genericObjectType, true)) { + // Skip missing classes during migration + continue; } + /** @var CommonDBTM $genericObjectTypeInstance */ $genericObjectTypeInstance = new $genericObjectType(); if ($DB->fieldExists($genericObjectTypeInstance->getTable(), "notepad")) { $query = "INSERT INTO `" . $notepad->getTable() . "` @@ -2461,25 +613,25 @@ public static function install(Migration $migration) FROM `" . $genericObjectTypeInstance->getTable() . "` WHERE notepad IS NOT NULL AND notepad <> ''"; - $DB->query($query) or die($DB->error()); + $DB->doQuery($query); } $migration->dropField($genericObjectTypeInstance->getTable(), "notepad"); $migration->migrationOneTable($genericObjectTypeInstance->getTable()); } - //Displayprefs + //Displayprefs $prefs = [10 => 6, 9 => 5, 8 => 4, 7 => 3, 6 => 2, 2 => 1, 4 => 1, 11 => 7, 12 => 8, - 14 => 10, 15 => 11 + 14 => 10, 15 => 11, ]; foreach ($prefs as $num => $rank) { if ( !countElementsInTable( "glpi_displaypreferences", - ['itemtype' => __CLASS__, 'num' => $num, 'users_id' => 0] + ['itemtype' => self::class, 'num' => $num, 'users_id' => 0], ) ) { $preference = new DisplayPreference(); - $tmp['itemtype'] = __CLASS__; + $tmp['itemtype'] = self::class; $tmp['num'] = $num; $tmp['rank'] = $rank; $tmp['users_id'] = 0; @@ -2502,19 +654,18 @@ public static function uninstall() /** @var DBmysql $DB */ global $DB; - //Delete references to PluginGenericobjectType in the following tables - self::deleteItemtypeReferencesInGLPI(__CLASS__); + //Delete references to PluginGenericobjectType in the following tables + self::deleteItemtypeReferencesInGLPI(self::class); - foreach ($DB->request("glpi_plugin_genericobject_types") as $type) { - //Delete references to PluginGenericobjectType in the following tables + foreach ($DB->request(['FROM' => 'glpi_plugin_genericobject_types']) as $type) { + //Delete references to PluginGenericobjectType in the following tables self::deleteItemtypeReferencesInGLPI($type['itemtype']); - //Dropd files and classes + //Dropd files and classes self::deleteItemTypeFilesAndClasses($type['name'], getTableForItemType($type['itemtype']), $type['itemtype']); } - //Delete table - $query = "DROP TABLE IF EXISTS `glpi_plugin_genericobject_types`"; - $DB->query($query) or die($DB->error()); + //Delete table + $DB->dropTable('glpi_plugin_genericobject_types', true); } @@ -2523,14 +674,14 @@ public static function getIcon() return "fas fa-car"; } - /** - * Normalize itemtype and name for all types. - * This method will ensure that new normalization rules will be taken into account - * during migration from an old version without loosing existing data. - * - * @param Migration $migration - * @return void - */ + /** + * Normalize itemtype and name for all types. + * This method will ensure that new normalization rules will be taken into account + * during migration from an old version without loosing existing data. + * + * @param Migration $migration + * @return void + */ private static function normalizeNamesAndItemtypes(Migration $migration) { /** @var DBmysql $DB */ @@ -2541,7 +692,7 @@ private static function normalizeNamesAndItemtypes(Migration $migration) [ 'FROM' => self::getTable(), 'ORDER' => 'name', - ] + ], ); foreach ($types_iterator as $type) { @@ -2559,7 +710,7 @@ private static function normalizeNamesAndItemtypes(Migration $migration) $old_name, $new_name, $old_itemtype, - $new_itemtype + $new_itemtype, ); $DB->update( @@ -2568,26 +719,26 @@ private static function normalizeNamesAndItemtypes(Migration $migration) 'name' => $new_name, 'itemtype' => $new_itemtype, ], - ['id' => $type['id']] + ['id' => $type['id']], ); $DB->update( self::getTable(), [ - 'linked_itemtypes' => new \QueryExpression( + 'linked_itemtypes' => new QueryExpression( 'REPLACE(' . $DB->quoteName('linked_itemtypes') . ',' . $DB->quoteValue('"' . $old_itemtype . '"') // itemtype is surrounded by quotes . ',' . $DB->quoteValue('"' . $new_itemtype . '"') // itemtype is surrounded by quotes - . ')' + . ')', ), ], - ['linked_itemtypes' => ['LIKE', '%"' . $old_itemtype . '"%']] + ['linked_itemtypes' => ['LIKE', '%"' . $old_itemtype . '"%']], ); - // Handle dropdowns related to itemtype + // Handle dropdowns related to itemtype $table = getTableForItemType($new_itemtype); $fields = $DB->listFields($table); foreach ($fields as $field => $options) { @@ -2602,8 +753,8 @@ private static function normalizeNamesAndItemtypes(Migration $migration) str_replace( "glpi_plugin_genericobject_", "", - $dropdown_old_table - ) + $dropdown_old_table, + ), ); $dropdown_old_itemtype = 'PluginGenericobject' . ucfirst($dropdown_old_name); $dropdown_new_name = self::filterInput($dropdown_old_name); @@ -2613,7 +764,7 @@ private static function normalizeNamesAndItemtypes(Migration $migration) $dropdown_old_name == $dropdown_new_name && $dropdown_old_itemtype == $dropdown_new_itemtype ) { - continue; + continue; } self::updateNameAndItemtype( @@ -2621,7 +772,7 @@ private static function normalizeNamesAndItemtypes(Migration $migration) $dropdown_old_name, $dropdown_new_name, $dropdown_old_itemtype, - $dropdown_new_itemtype + $dropdown_new_itemtype, ); } } @@ -2630,17 +781,17 @@ private static function normalizeNamesAndItemtypes(Migration $migration) ProfileRight::cleanAllPossibleRights(); // Clean all possible rights are their name may have change } - /** - * Update itemtype and/or name for a given itemtype. - * - * @param Migration $migration - * @param string $old_name Current type name in database - * @param string $new_name New type name to use - * @param string $old_itemtype Current itemtype - * @param string $new_itemtype New itemtype to use - * - * @return void - */ + /** + * Update itemtype and/or name for a given itemtype. + * + * @param Migration $migration + * @param string $old_name Current type name in database + * @param string $new_name New type name to use + * @param string $old_itemtype Current itemtype + * @param string $new_itemtype New itemtype to use + * + * @return void + */ private static function updateNameAndItemtype( Migration $migration, $old_name, @@ -2675,57 +826,55 @@ private static function updateNameAndItemtype( self::getCompleteConstantFilename($new_name), ]; - // Rename locale folder and map files + // Rename locale folder and map files if (is_dir($old_locale_dir) && $old_locale_dir != $new_locale_dir) { if (rename($old_locale_dir, $new_locale_dir)) { - // Add all locale files to destination files + // Add all locale files to destination files foreach (glob($new_locale_dir . '/*.php') as $old_filename) { $destination_files[] = preg_replace( '/(.*\/)' . preg_quote($old_systemname, '/') . '([^\/]*)$/', '$1' . $new_systemname . '$2', - $old_filename + $old_filename, ); } } else { - $migration->displayWarning( + $migration->displayMessage( sprintf('Unable to rename "%s" locale directory to "%s"', $old_locale_dir, $new_locale_dir), - true ); } } - // Handle *_item class table/itemtype + // Handle *_item class table/itemtype if ($DB->tableExists(getTableForItemType($old_itemtype . '_Item'))) { $migration->renameItemtype($old_itemtype . '_Item', $new_itemtype . '_Item'); $migration->executeMigration(); // Execute migration to flush updates on tables that may be renamed } - // Add all constant files as they may contains foreign keys to update + // Add all constant files as they may contains foreign keys to update foreach (glob(GENERICOBJECT_FIELDS_PATH . '/*.php') as $constant_filename) { $destination_files[] = $constant_filename; } - // Rename files (replace "/{$old name}*" by "/{$new_system_name}*") + // Rename files (replace "/{$old name}*" by "/{$new_system_name}*") $migration->displayMessage( - sprintf('Rename files related to "%s" itemtype and update their content', $old_itemtype) + sprintf('Rename files related to "%s" itemtype and update their content', $old_itemtype), ); foreach ($destination_files as $new_filename) { $old_filename = preg_replace( '/(.*\/)' . preg_quote($new_systemname, '/') . '([^\/]*)$/', '$1' . $old_systemname . '$2', - $new_filename + $new_filename, ); if (!file_exists($old_filename)) { - // Do nothing if old file does not exists - continue; + // Do nothing if old file does not exists + continue; } if ($old_filename != $new_filename) { if (!rename($old_filename, $new_filename)) { - $migration->displayWarning( + $migration->displayMessage( sprintf('Unable to rename "%s" file to "%s"', $old_filename, $new_filename), - true ); continue; } @@ -2737,9 +886,8 @@ private static function updateNameAndItemtype( $file_contents = file_get_contents($new_filename); if (!$file_contents) { - $migration->displayWarning( + $migration->displayMessage( sprintf('Unable to read "%s" file contents', $new_filename), - true ); continue; } @@ -2751,100 +899,24 @@ private static function updateNameAndItemtype( [$old_itemtype, $old_fkey, $old_fkey_truncated], [$new_itemtype, $new_fkey, $new_fkey_truncated], $file_contents, - $replace_count + $replace_count, ); if ($replace_count > 0 && !file_put_contents($new_filename, $file_contents)) { - $migration->displayWarning( - sprintf('Unable to update "%s" file contents', $new_filename), - true - ); + $migration->displayMessage( + sprintf('Unable to update "%s" file contents', $new_filename), + ); } } - // Update profile rights + // Update profile rights if ($old_itemtype != $new_itemtype) { $migration->addPostQuery( $DB->buildUpdate( ProfileRight::getTable(), ['name' => PluginGenericobjectProfile::getProfileNameForItemtype($new_itemtype)], - ['name' => PluginGenericobjectProfile::getProfileNameForItemtype($old_itemtype)] - ) - ); - } - } - - /** - * Given an impact icon filename, return the expected full or relative path - * where it should be stored - * - * @param string $filename - * @param string $itemtype Impact itemtype, needed to avoid filename colision - * @param bool $relative (default: false) - * - * @return null|string - */ - public static function getImpactIconFileStoragePath( - ?string $filename, - string $itemtype, - bool $relative = false - ): ?string { - if (empty($filename)) { - return null; - } - - // Make sure $filename does not contains any directory changes like ".." - if ($filename != pathinfo($filename)['basename']) { - trigger_error( - "Trying to access forbidden file: $filename", - E_USER_WARNING + ['name' => PluginGenericobjectProfile::getProfileNameForItemtype($old_itemtype)], + ), ); - return null; - } - - $filename = "{$itemtype}_{$filename}"; - $path = GLPI_PLUGIN_DOC_DIR . "/genericobject/impact_icons/$filename"; - - if ($relative) { - $path = str_replace(GLPI_ROOT, "", $path); - } - - return $path; - } - - /** - * Get file path to impact icon file - * - * @return string|null - */ - public function getImpactIconFilePath(): ?string - { - if (empty($this->fields['impact_icon'])) { - return null; - } - - $path = self::getImpactIconFileStoragePath( - $this->fields['impact_icon'], - $this->fields['itemtype'] - ); - if (empty($path) || !file_exists($path)) { - return null; - } - - return $path; - } - - /** - * Get public URL to impact icon file - * - * @return null|string - */ - public function getImpactIconUrl($full = true): ?string - { - // Check that the file exist - if (!$this->getImpactIconFilePath()) { - return null; } - - return Plugin::getWebDir('genericobject', $full) . "/front/getimpacticon.php?itemtype=" . $this->fields['itemtype']; } } diff --git a/inc/typefamily.class.php b/inc/typefamily.class.php index 87e9cb97..364c6561 100644 --- a/inc/typefamily.class.php +++ b/inc/typefamily.class.php @@ -29,7 +29,7 @@ */ if (!defined('GLPI_ROOT')) { - die("Sorry. You can't access directly to this file"); + throw new RuntimeException('Direct access to this file is not allowed'); } class PluginGenericobjectTypeFamily extends CommonDropdown @@ -38,7 +38,7 @@ class PluginGenericobjectTypeFamily extends CommonDropdown public static function getTypeName($nb = 0) { - return __('Family of type of objects', 'genericobject'); + return __s('Family of type of objects', 'genericobject'); } public static function install(Migration $migration) @@ -50,7 +50,7 @@ public static function install(Migration $migration) $default_collation = DBConnection::getDefaultCollation(); $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); - $table = getTableForItemType(__CLASS__); + $table = getTableForItemType(self::class); if (!$DB->tableExists($table)) { $query = "CREATE TABLE `$table` ( `id` INT {$default_key_sign} NOT NULL AUTO_INCREMENT, @@ -62,7 +62,7 @@ public static function install(Migration $migration) KEY `date_mod` (`date_mod`), KEY `date_creation` (`date_creation`) ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; - $DB->query($query) or die($DB->error()); + $DB->doQuery($query); } } @@ -71,44 +71,7 @@ public static function uninstall() /** @var DBmysql $DB */ global $DB; - $table = getTableForItemType(__CLASS__); - if ($DB->tableExists($table)) { - $query = "DROP TABLE IF EXISTS `$table`"; - $DB->query($query) or die($DB->error()); - } - } - - public static function getFamilies() - { - /** @var DBmysql $DB */ - global $DB; - - $query = "SELECT f.id as id, f.name as name, t.itemtype as itemtype - FROM glpi_plugin_genericobject_typefamilies as f - LEFT JOIN glpi_plugin_genericobject_types AS t - ON (f.id = t.plugin_genericobject_typefamilies_id) - WHERE t.id IN (SELECT DISTINCT `id` - FROM glpi_plugin_genericobject_types - WHERE is_active=1)"; - $families = []; - foreach ($DB->request($query) as $fam) { - $itemtype = $fam['itemtype']; - if ($itemtype::canCreate()) { - $families[$fam['id']] = $fam['name']; - } - } - return $families; - } - - - public static function getItemtypesByFamily($families_id) - { - return getAllDataFromTable( - 'glpi_plugin_genericobject_types', - [ - 'plugin_genericobject_typefamilies_id' => $families_id, - 'is_active' => 1 - ] + ['ORDER' => 'name'] - ); + $table = getTableForItemType(self::class); + $DB->dropTable($table, true); } } diff --git a/index.php b/index.php index cf9e4c8e..32fbd46e 100644 --- a/index.php +++ b/index.php @@ -28,66 +28,15 @@ * ------------------------------------------------------------------------- */ -define('GLPI_ROOT', '../..'); -include(GLPI_ROOT . "/inc/includes.php"); - -if (isset($_GET['itemtypes_id']) && $_GET['itemtypes_id'] != '') { - $type = new PluginGenericobjectType(); - $type->getFromDB($_GET['itemtypes_id']); - Html::redirect(Toolbox::getItemTypeSearchURL($type->fields['itemtype'])); -} else { - $types = PluginGenericobjectType::getTypesByFamily(); - foreach ($types as $family => $typeData) { - foreach ($typeData as $ID => $value) { - if (!Session::haveRight($value['itemtype'], READ)) { - unset($types[$family][$ID]); - } - } - } - - //There's only one family - if (count($types) == 1) { - //There's only one itemtype ? If yes, then automatically - //redirect to the search engine - if (key($types) == null) { - $mytypes = $types; - $tmp = array_pop($mytypes); - if (count($tmp) == 1) { - Html::redirect(Toolbox::getItemTypeSearchURL(key($tmp))); - } - } - } - - Html::header( - __("Objects management", "genericobject"), - $_SERVER['PHP_SELF'], - "plugins", - "genericobject" - ); - - foreach ($types as $family => $typeData) { - $PluginGenericobjectTypefamily = new PluginGenericobjectTypefamily(); - $PluginGenericobjectTypefamily->getFromDB($family); - - echo "
" . __("Link to other objects", "genericobject") . "
" . _n("Type", "Types", 2) . ""; - echo ""; - echo "
"; - if ($family == 0) { - echo ""; - } else { - echo ""; - } - if (!count($types)) { - echo ""; - } else { - foreach ($typeData as $ID => $value) { - echo ""; - } - } - echo "
" . __("Empty family", "genericobject") . "
" . $PluginGenericobjectTypefamily->getField("name") . "
" . __("No item to display") . "
"; - echo ""; - $itemtype = $value['itemtype']; - echo $itemtype::getTypeName(); - echo "
"; - } - - Html::footer(); -} +// Check if user has admin rights +Session::checkRight('config', UPDATE); + +// Show EOL message +$message = sprintf( + __('GenericObject v%s is End-of-Life. All genericobject functionality is now available in GLPI 11 core. Check migration status or use native custom assets.', 'genericobject'), + PLUGIN_GENERICOBJECT_VERSION, +); +Session::addMessageAfterRedirect($message, true, WARNING); + +// Redirect to migration status page +Html::redirect($CFG_GLPI['root_doc'] . '/plugins/genericobject/front/migration_status.php'); diff --git a/objects/front.form.tpl b/objects/front.form.tpl deleted file mode 100644 index d1d50e6c..00000000 --- a/objects/front.form.tpl +++ /dev/null @@ -1,35 +0,0 @@ -. - -------------------------------------------------------------------------- - @package genericobject - @author the genericobject plugin team - @copyright Copyright (c) 2010-2017 Genericobject plugin team - @license GPLv2+ - http://www.gnu.org/licenses/gpl.txt - @link https://github.com/pluginsGLPI/genericobject - @link http://www.glpi-project.org/ - @since 2009 - ---------------------------------------------------------------------- */ - -/** - * This file is automatically managed by genericobject plugin. Do not edit it ! - */ - -include ("../../../inc/includes.php"); - -$dropdown = new %%CLASSNAME%%(); -include (GLPI_ROOT . "/front/dropdown.common.form.php"); diff --git a/objects/front.tpl b/objects/front.tpl deleted file mode 100644 index 6a132b91..00000000 --- a/objects/front.tpl +++ /dev/null @@ -1,38 +0,0 @@ -. - -------------------------------------------------------------------------- - @package genericobject - @author the genericobject plugin team - @copyright Copyright (c) 2010-2017 Genericobject plugin team - @license GPLv2+ - http://www.gnu.org/licenses/gpl.txt - @link https://github.com/pluginsGLPI/genericobject - @link http://www.glpi-project.org/ - @since 2009 - ---------------------------------------------------------------------- */ -include ("../../../inc/includes.php"); - -/** - * This file is automatically managed by genericobject plugin. Do not edit it ! - */ - -Html::header(%%CLASSNAME%%::getTypeName(), $_SERVER['PHP_SELF'], "plugins", "genericobject", - "%%CLASSNAME%%"); - -Search::show('%%CLASSNAME%%'); - -Html::footer(); diff --git a/objects/generic.class.tpl b/objects/generic.class.tpl deleted file mode 100644 index c8d14ef6..00000000 --- a/objects/generic.class.tpl +++ /dev/null @@ -1,45 +0,0 @@ -. - -------------------------------------------------------------------------- - @package genericobject - @author the genericobject plugin team - @copyright Copyright (c) 2010-2017 Genericobject plugin team - @license GPLv2+ - http://www.gnu.org/licenses/gpl.txt - @link https://github.pluginsGLPI/genericobject - @link http://www.glpi-project.org/ - @since 2009 - ---------------------------------------------------------------------- */ - -/** - * This class is automatically managed by genericobject plugin. Do not edit it ! - */ -class %%CLASSNAME%% extends PluginGenericobjectObject { - - static $rightname = ''; - - static function getFormURL($full=true) { - return Toolbox::getItemTypeFormURL( parent::class , $full) . - "?itemtype=".get_called_class(); - } - static function getSearchURL($full=true) { - return Toolbox::getItemTypeSearchURL( parent::class , $full) . - "?itemtype=".get_called_class(); - - } -} - diff --git a/objects/generic.dropdown.class.tpl b/objects/generic.dropdown.class.tpl deleted file mode 100644 index de972f69..00000000 --- a/objects/generic.dropdown.class.tpl +++ /dev/null @@ -1,33 +0,0 @@ -. - -------------------------------------------------------------------------- - @package genericobject - @author the genericobject plugin team - @copyright Copyright (c) 2010-2017 Genericobject plugin team - @license GPLv2+ - http://www.gnu.org/licenses/gpl.txt - @link https://github.com/pluginsGLPI/genericobject - @link http://www.glpi-project.org/ - @since 2009 - ---------------------------------------------------------------------- */ - -/** - * This class is automatically managed by genericobject plugin. Do not modify it ! - */ -class %%CLASSNAME%% extends %%EXTENDS%% { - public $linked_itemtype = "%%LINKED_ITEMTYPE%%"; -} diff --git a/objects/generic.form.tpl b/objects/generic.form.tpl deleted file mode 100644 index 1daf17fb..00000000 --- a/objects/generic.form.tpl +++ /dev/null @@ -1,35 +0,0 @@ -. - -------------------------------------------------------------------------- - @package genericobject - @author the genericobject plugin team - @copyright Copyright (c) 2010-2017 Genericobject plugin team - @license GPLv2+ - http://www.gnu.org/licenses/gpl.txt - @link https://github.com/pluginsGLPI/genericobject - @link http://www.glpi-project.org/ - @since 2009 - ---------------------------------------------------------------------- */ - -/** - * This file is automatically managed by genericobject plugin. Do not edit it ! - */ - -include ("../../../inc/includes.php"); - -$item = new %%CLASSNAME%%(); -include (GENERICOBJECT_DIR."/front/object.form.php"); diff --git a/objects/locale.tpl b/objects/locale.tpl deleted file mode 100644 index 0e90ecaa..00000000 --- a/objects/locale.tpl +++ /dev/null @@ -1,29 +0,0 @@ -. - -------------------------------------------------------------------------- - @package genericobject - @author the genericobject plugin team - @copyright Copyright (c) 2010-2017 Genericobject plugin team - @license GPLv2+ - http://www.gnu.org/licenses/gpl.txt - @link https://github.com/pluginsGLPI/genericobject - @link http://www.glpi-project.org/ - @since 2009 - ---------------------------------------------------------------------- */ -global $LANG; - -$LANG['genericobject']['%%CLASSNAME%%'][0]="%%NAME%%"; diff --git a/objects/object_item.class.tpl b/objects/object_item.class.tpl deleted file mode 100644 index 0131e4fd..00000000 --- a/objects/object_item.class.tpl +++ /dev/null @@ -1,44 +0,0 @@ -. - -------------------------------------------------------------------------- - @package genericobject - @author the genericobject plugin team - @copyright Copyright (c) 2010-2017 Genericobject plugin team - @license GPLv2+ - http://www.gnu.org/licenses/gpl.txt - @link https://github.com/pluginsGLPI/genericobject - @link http://www.glpi-project.org/ - @since 2009 - ---------------------------------------------------------------------- */ - -if (!defined('GLPI_ROOT')){ - die("Sorry. You can't access directly to this file"); -} - -class %%CLASSNAME%% extends PluginGenericobjectObject_Item { - - public $dohistory = true; - - // From CommonDBRelation - static public $itemtype_1 = '%%SOURCEOBJECT%%'; - static public $items_id_1 = '%%FOREIGNKEY%%'; - - static public $itemtype_2 = 'itemtype'; - static public $items_id_2 = 'items_id'; - static public $checkItem_2_Rights = self::HAVE_VIEW_RIGHT_ON_ITEM; -} - diff --git a/objects/objectinjection.class.tpl b/objects/objectinjection.class.tpl deleted file mode 100644 index 5ee3fa5c..00000000 --- a/objects/objectinjection.class.tpl +++ /dev/null @@ -1,91 +0,0 @@ -. - -------------------------------------------------------------------------- - @package genericobject - @author the genericobject plugin team - @copyright Copyright (c) 2010-2017 Genericobject plugin team - @license GPLv2+ - http://www.gnu.org/licenses/gpl.txt - @link https://github.com/pluginsGLPI/genericobject - @link http://www.glpi-project.org/ - @since 2009 - ---------------------------------------------------------------------- */ - -/** - * This file is automatically managed by genericobject plugin. Do not edit it ! - */ - -if (!defined('GLPI_ROOT')) { - die("Sorry. You can't access directly to this file"); -} - -class %%INJECTIONCLASS%% extends %%CLASSNAME%% - implements PluginDatainjectionInjectionInterface { - - static function getTable($classname = null) { - - $parenttype = get_parent_class(); - return $parenttype::getTable(); - - } - - function isPrimaryType() { - return true; - } - - function connectedTo() { - return []; - } - - /** - * Standard method to add an object into glpi - * - * @param values fields to add into glpi - * @param options options used during creation - * @return an array of IDs of newly created objects : for example [Computer=>1, Networkport=>10] - * - **/ - function addOrUpdateObject($values = [], $options = []) { - - $lib = new PluginDatainjectionCommonInjectionLib($this, $values, $options); - $lib->processAddOrUpdate(); - return $lib->getInjectionResults(); - } - - /** - * Get search options formatted for injection mapping usage in datainjection plugin. - * - * @return array - */ - function getOptions($primary_type = '') { - $plugin = new Plugin(); - if (!$plugin->isActivated('datainjection')) { - return []; - } - - return PluginDatainjectionCommonInjectionLib::addToSearchOptions( - Search::getOptions(get_parent_class($this)), - [ - 'ignore_fields' => PluginDatainjectionCommonInjectionLib::getBlacklistedOptions( - get_parent_class($this) - ), - ], - $this - ); - } - -} diff --git a/phpstan.neon b/phpstan.neon index 60bb85d3..3905d94e 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,13 +1,13 @@ parameters: parallel: maximumNumberOfProcesses: 2 - level: 1 + level: 5 bootstrapFiles: - - ../../inc/based_config.php + - ../../stubs/glpi_constants.php + - ../../vendor/autoload.php paths: - inc - front - - ajax - hook.php - setup.php scanDirectories: diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 00000000..034c1222 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/rector.php b/rector.php new file mode 100644 index 00000000..e2ea9eb9 --- /dev/null +++ b/rector.php @@ -0,0 +1,98 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2009-2023 by GenericObject plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/genericobject + * ------------------------------------------------------------------------- + */ + +require_once __DIR__ . '/../../src/Plugin.php'; + +use Rector\Caching\ValueObject\Storage\FileCacheStorage; +use Rector\CodeQuality\Rector as CodeQuality; +use Rector\Config\RectorConfig; +use Rector\DeadCode\Rector as DeadCode; +use Rector\ValueObject\PhpVersion; + +return RectorConfig::configure() + ->withPaths([ + __DIR__ . '/fields', + __DIR__ . '/front', + __DIR__ . '/inc', + ]) + ->withPhpVersion(PhpVersion::PHP_82) + ->withCache( + cacheClass: FileCacheStorage::class, + cacheDirectory: sys_get_temp_dir() . '/genericobject-rector', + ) + ->withRootFiles() + ->withParallel(timeoutSeconds: 300) + ->withImportNames(removeUnusedImports: true) + ->withRules([ + CodeQuality\Assign\CombinedAssignRector::class, + CodeQuality\BooleanAnd\RemoveUselessIsObjectCheckRector::class, + CodeQuality\BooleanAnd\SimplifyEmptyArrayCheckRector::class, + CodeQuality\BooleanNot\ReplaceMultipleBooleanNotRector::class, + CodeQuality\Catch_\ThrowWithPreviousExceptionRector::class, + CodeQuality\Empty_\SimplifyEmptyCheckOnEmptyArrayRector::class, + CodeQuality\Expression\InlineIfToExplicitIfRector::class, + CodeQuality\Expression\TernaryFalseExpressionToIfRector::class, + CodeQuality\For_\ForRepeatedCountToOwnVariableRector::class, + CodeQuality\Foreach_\ForeachItemsAssignToEmptyArrayToAssignRector::class, + CodeQuality\Foreach_\ForeachToInArrayRector::class, + CodeQuality\Foreach_\SimplifyForeachToCoalescingRector::class, + CodeQuality\Foreach_\UnusedForeachValueToArrayKeysRector::class, + CodeQuality\FuncCall\ChangeArrayPushToArrayAssignRector::class, + CodeQuality\FuncCall\CompactToVariablesRector::class, + CodeQuality\FuncCall\InlineIsAInstanceOfRector::class, + CodeQuality\FuncCall\IsAWithStringWithThirdArgumentRector::class, + CodeQuality\FuncCall\RemoveSoleValueSprintfRector::class, + CodeQuality\FuncCall\SetTypeToCastRector::class, + CodeQuality\FuncCall\SimplifyFuncGetArgsCountRector::class, + CodeQuality\FuncCall\SimplifyInArrayValuesRector::class, + CodeQuality\FuncCall\SimplifyStrposLowerRector::class, + CodeQuality\FuncCall\UnwrapSprintfOneArgumentRector::class, + CodeQuality\Identical\BooleanNotIdenticalToNotIdenticalRector::class, + CodeQuality\Identical\SimplifyArraySearchRector::class, + CodeQuality\Identical\SimplifyConditionsRector::class, + CodeQuality\Identical\StrlenZeroToIdenticalEmptyStringRector::class, + CodeQuality\If_\CombineIfRector::class, + CodeQuality\If_\CompleteMissingIfElseBracketRector::class, + CodeQuality\If_\ConsecutiveNullCompareReturnsToNullCoalesceQueueRector::class, + CodeQuality\If_\ExplicitBoolCompareRector::class, + CodeQuality\If_\ShortenElseIfRector::class, + CodeQuality\If_\SimplifyIfElseToTernaryRector::class, + CodeQuality\If_\SimplifyIfNotNullReturnRector::class, + CodeQuality\If_\SimplifyIfNullableReturnRector::class, + CodeQuality\If_\SimplifyIfReturnBoolRector::class, + CodeQuality\Include_\AbsolutizeRequireAndIncludePathRector::class, + CodeQuality\LogicalAnd\AndAssignsToSeparateLinesRector::class, + CodeQuality\LogicalAnd\LogicalToBooleanRector::class, + CodeQuality\NotEqual\CommonNotEqualRector::class, + CodeQuality\Ternary\UnnecessaryTernaryExpressionRector::class, + DeadCode\Assign\RemoveUnusedVariableAssignRector::class, + ]) + ->withPhpSets(php74: true) // apply PHP sets up to PHP 7.4 +; diff --git a/setup.php b/setup.php index 93b0f56b..411fa3cb 100644 --- a/setup.php +++ b/setup.php @@ -28,12 +28,12 @@ * ------------------------------------------------------------------------- */ -define('PLUGIN_GENERICOBJECT_VERSION', '2.14.14'); +define('PLUGIN_GENERICOBJECT_VERSION', '3.0.0'); // Minimal GLPI version, inclusive -define("PLUGIN_GENERICOBJECT_MIN_GLPI", "10.0.0"); +define("PLUGIN_GENERICOBJECT_MIN_GLPI", "11.0.0"); // Maximum GLPI version, exclusive -define("PLUGIN_GENERICOBJECT_MAX_GLPI", "10.0.99"); +define("PLUGIN_GENERICOBJECT_MAX_GLPI", "11.0.99"); if (!defined("GENERICOBJECT_DIR")) { define("GENERICOBJECT_DIR", Plugin::getPhpDir("genericobject")); @@ -94,7 +94,7 @@ } $go_autoloader = new PluginGenericobjectAutoloader([ - GENERICOBJECT_CLASS_PATH + GENERICOBJECT_CLASS_PATH, ]); $go_autoloader->register(); @@ -108,122 +108,15 @@ function plugin_init_genericobject() { /** * @var array $PLUGIN_HOOKS - * @var array $GO_BLACKLIST_FIELDS - * @var array $GENERICOBJECT_PDF_TYPES - * @var array $GO_LINKED_TYPES - * @var array $GO_READONLY_FIELDS - * @var array $CFG_GLPI */ - global $PLUGIN_HOOKS, $GO_BLACKLIST_FIELDS, - $GENERICOBJECT_PDF_TYPES, $GO_LINKED_TYPES, $GO_READONLY_FIELDS, $CFG_GLPI; - - $GO_READONLY_FIELDS = ["is_helpdesk_visible", "comment", "ticket_tco"]; - - $GO_BLACKLIST_FIELDS = ["itemtype", "table", "is_deleted", "id", "entities_id", - "is_recursive", "is_template", "notepad", "template_name", - "date_mod", "name", "is_helpdesk_visible", "comment", - "date_creation", "ticket_tco" - ]; - - $GO_LINKED_TYPES = ['Computer', 'Phone', 'Peripheral', 'Software', 'Monitor', - 'Printer', 'NetworkEquipment' - ]; + global $PLUGIN_HOOKS; $PLUGIN_HOOKS['csrf_compliant']['genericobject'] = true; - $GENERICOBJECT_PDF_TYPES = []; - - if (Plugin::isPluginActive("genericobject") && isset($_SESSION['glpiactiveprofile'])) { - //if treeview is installed - if (Plugin::isPluginActive("treeview") && class_exists('PluginTreeviewConfig')) { - //foreach type in genericobject - foreach (PluginGenericobjectType::getTypes() as $itemtype => $value) { - //check if location_id field exist - $fields_in_db = PluginGenericobjectSingletonObjectField::getInstance($itemtype); - $objecttype = PluginGenericobjectType::getInstance($itemtype); - if (isset($fields_in_db['locations_id']) && $objecttype->canUsePluginTreeview()) { - //register class - PluginTreeviewConfig::registerType($itemtype); - $PLUGIN_HOOKS['treeview'][$itemtype] = Plugin::getWebDir('genericobject') . '/pics/default-icon16.png'; - - //add hook for overload item show form url - $PLUGIN_HOOKS['treeview_params']['genericobject'] = [ - 'PluginGenericobjectObject', - 'showGenericObjectTreeview' - ]; - - //add hook for overload search form url of itemtype - $PLUGIN_HOOKS['treeview_search_url_parent_node']['genericobject'] = [ - 'PluginGenericobjectObject', - 'getParentNodeSearchUrl' - ]; - } - } - } - - $PLUGIN_HOOKS['change_profile']['genericobject'] = [ - 'PluginGenericobjectProfile', - 'changeProfile' - ]; - - plugin_genericobject_includeCommonFields(); - $PLUGIN_HOOKS['use_massive_action']['genericobject'] = 1; - - // add css styles - $PLUGIN_HOOKS['add_css']['genericobject'] = [ - "css/styles.css" - ]; - // Display a menu entry ? - $PLUGIN_HOOKS['menu_toadd']['genericobject'] = [ - 'config' => 'PluginGenericobjectType', - 'assets' => 'PluginGenericobjectObject' - ]; + // Config page + if (Plugin::isPluginActive("genericobject") && isset($_SESSION['glpiactiveprofile']) && Session::haveRight('config', READ)) { - // Config page - if (Session::haveRight('config', READ)) { - $PLUGIN_HOOKS['config_page']['genericobject'] = 'front/type.php'; - } - - $PLUGIN_HOOKS['assign_to_ticket']['genericobject'] = true; - $PLUGIN_HOOKS['use_massive_action']['genericobject'] = 1; - - $PLUGIN_HOOKS['post_init']['genericobject'] = 'plugin_post_init_genericobject'; - $PLUGIN_HOOKS['plugin_datainjection_populate']['genericobject'] = "plugin_datainjection_populate_genericobject"; - - $PLUGIN_HOOKS['formcreator_get_glpi_object_types']['genericobject'] = [ - PluginGenericobjectType::getType(), - 'getTypesForFormcreator' - ]; - - // Add every genericobject item's to the list of itemtypes for which the - // impact analysis can be enabled - foreach ((new PluginGenericobjectType())->find([]) as $row) { - if (empty($row['impact_icon'])) { - $icon = ""; // Will fallback to default impact icon - } else { - $obj = new PluginGenericobjectType(); - $obj->getFromDB($row['id']); - $icon = $obj->getImpactIconUrl(false) ?? ""; - } - - $CFG_GLPI['impact_asset_types'][$row['itemtype']] = $icon; - } - } -} - -function plugin_post_init_genericobject() -{ - Plugin::registerClass( - 'PluginGenericobjectProfile', - ['addtabon' => ['Profile', 'PluginGenericobjectType']] - ); - - - foreach (PluginGenericobjectType::getTypes() as $id => $objecttype) { - $itemtype = $objecttype['itemtype']; - if (class_exists($itemtype)) { - $itemtype::registerType(); - } + $PLUGIN_HOOKS['config_page']['genericobject'] = 'front/eol_info.php'; } } @@ -236,7 +129,7 @@ function plugin_post_init_genericobject() function plugin_version_genericobject() { return [ - 'name' => __("Objects management", "genericobject"), + 'name' => __s("Objects management (Migration Only)", "genericobject"), 'version' => PLUGIN_GENERICOBJECT_VERSION, 'author' => "Teclib' & siprossii", 'homepage' => 'https://github.com/pluginsGLPI/genericobject', @@ -246,55 +139,7 @@ function plugin_version_genericobject() 'min' => PLUGIN_GENERICOBJECT_MIN_GLPI, 'max' => PLUGIN_GENERICOBJECT_MAX_GLPI, 'dev' => true, //Required to allow 9.2-dev - ] - ] - ]; -} - - -function plugin_genericobject_haveTypeRight($itemtype, $right) -{ - switch ($itemtype) { - case 'PluginGenericobjectType': - return Session::haveRight("config", $right); - default: - return Session::haveRight($itemtype, $right); - } -} - -function plugin_genericobject_includeCommonFields($force = false) -{ - $includes = [ - sprintf('%s/fields/field.constant.php', GENERICOBJECT_DIR), // Default common fields constants + ], + ], ]; - - // User locales for common fields - if ( - isset($_SESSION['glpilanguage']) - && file_exists($locale_file = sprintf('%s/fields.%s.php', GENERICOBJECT_LOCALES_PATH, $_SESSION['glpilanguage'])) - ) { - $includes[] = $locale_file; - } elseif (file_exists($locale_file = sprintf('%s/fields.%s.php', GENERICOBJECT_LOCALES_PATH, 'en_GB'))) { - $includes[] = $locale_file; - } - - // User common fields constants - if (file_exists($fields_file = sprintf('%s/field.constant.php', GENERICOBJECT_FIELDS_PATH))) { - $includes[] = $fields_file; - } - - foreach ($includes as $include) { - if (!$force) { - include_once($include); - } else { - include($include); - } - } -} - -function plugin_genericobject_haveRight($class, $right) -{ - - $right_name = PluginGenericobjectProfile::getProfileNameForItemtype($class); - return Session::haveRight($right_name, $right); } diff --git a/templates/eol_info.html.twig b/templates/eol_info.html.twig new file mode 100644 index 00000000..5fb3c84b --- /dev/null +++ b/templates/eol_info.html.twig @@ -0,0 +1,145 @@ +{# + # ------------------------------------------------------------------------- + # GenericObject plugin for GLPI + # ------------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of GenericObject. + # + # GenericObject is free software; you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation; either version 3 of the License, or + # (at your option) any later version. + # + # GenericObject 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 General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with GenericObject. If not, see . + # ------------------------------------------------------------------------- + # @copyright Copyright (C) 2009-2023 by GenericObject plugin team. + # @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + # @link https://github.com/pluginsGLPI/genericobject + # ------------------------------------------------------------------------- + #} + +
+
+
+
+ {# Header with icon and title #} +
+
+
+ +
+
+

+ {{ __('GenericObject End of Life Notice', 'genericobject') }} +

+

+ {{ __('Migration guidance and information', 'genericobject') }} +

+
+
+
+ + {# Body #} +
+ {# EOL Notice Banner #} +
+
+ +
+
{{ __('Important Notice', 'genericobject') }}
+

+ {{ __("GenericObject v%s has reached End of Life (EOL). This version only provides migration assistance to help you switch to GLPI 11's asset definition", 'genericobject')|format(plugin_version) }} +

+
+
+
+ + {# Migration Information Grid #} +
+
+
+
+
+ + {{ __('What changed?', 'genericobject') }} +
+
+
+
    +
  • + + {{ __('GLPI 11 now has native custom asset creation capabilities', 'genericobject') }} +
  • +
  • + + {{ __('All Genericobject features are available in GLPI core', 'genericobject') }} +
  • +
  • + + {{ __('Better integration with GLPI workflows', 'genericobject') }} +
  • +
  • + + {{ __('Improved performance and security', 'genericobject') }} +
  • +
+
+
+
+ +
+
+
+
+ + {{ __('Next steps', 'genericobject') }} +
+
+
+
    +
  • + + {{ __('Review your existing genericobject assets', 'genericobject') }} +
  • +
  • + + {{ __('Migrate to GLPI 11 native asset definition', 'genericobject') }} +
  • +
  • + + {{ __('Test the new asset system', 'genericobject') }} +
  • +
  • + + {{ __('Uninstall GenericObject plugin when ready', 'genericobject') }} +
  • +
+
+
+
+
+ + {# Action buttons #} + + +
+
+
+
+
diff --git a/templates/migration_status.html.twig b/templates/migration_status.html.twig new file mode 100644 index 00000000..79a4377d --- /dev/null +++ b/templates/migration_status.html.twig @@ -0,0 +1,299 @@ +{# + # ------------------------------------------------------------------------- + # GenericObject plugin for GLPI + # ------------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of GenericObject. + # + # GenericObject is free software; you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation; either version 3 of the License, or + # (at your option) any later version. + # + # GenericObject 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 General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with GenericObject. If not, see . + # ------------------------------------------------------------------------- + # @copyright Copyright (C) 2009-2023 by GenericObject plugin team. + # @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + # @link https://github.com/pluginsGLPI/genericobject + # ------------------------------------------------------------------------- + #} + +{# Page Header #} +
+
+ +
+
+

{{ __('GenericObject Migration Status', 'genericobject') }}

+

{{ __('End of Life migration tool for GLPI 11', 'genericobject') }}

+
+
+
+
+ {# EOL Warning Banner #} +
+
+ +
+
{{ __('End of Life Notice', 'genericobject') }}
+

+ {{ __('GenericObject v3.0.0 is an End-of-Life version. All custom asset creation functionality has been moved to GLPI 11 native asset definition.', 'genericobject') }} +

+
+
+
+ + {# Migration Status Card #} +
+
+

+ + {{ __('Migration Status', 'genericobject') }} +

+
+
+ {# Set pagination variables #} + {% set start = _get.start|default(0) %} + {% set limit = _get.limit|default(user_pref('list_limit')) %} + {% set total_count = genericobject_types|length %} + + {# Calculate pagination #} + {% set paginated_types = genericobject_types|slice(start, limit) %} + + {# Display pagination controls at the top #} + {{ include('components/pager.html.twig', { + 'count': total_count, + 'start': start, + 'limit': limit, + 'href': 'migration_status.php', + 'short_display': true, + 'no_limit_display': false + }) }} + +
+ {% for key, genericobject_type in paginated_types %} +
+
+ {% if customassets[genericobject_type.name] and customassets[genericobject_type.name].icon %} + + {% else %} + + {% endif %} +

+ {{ genericobject_type.name }} +

+
+ +
+ {% if customassets[genericobject_type.name] %} +
+ + {{ __('Migrated', 'genericobject') }} +
+
+ {{ __('Items Migrated:', 'genericobject') }} + + {{ customassets[genericobject_type.name].items }} + +
+ + {% else %} +
+ + {{ __('Not Migrated', 'genericobject') }} +
+
+ {{ __('Items Migrated:', 'genericobject') }} + 0 +
+
+ + +
+ {% endif %} +
+
+ {% endfor %} +
+ {# Display pagination controls at the bottom #} + {{ include('components/pager.html.twig', { + 'count': total_count, + 'start': start, + 'limit': limit, + 'href': 'migration_status.php', + 'short_display': false, + 'no_limit_display': false + }) }} +
+
+ +
+
+

+ + {{ __('How to Migrate', 'genericobject') }} +

+
+
+
+
+ +
+

{{ __('Command Line Migration Required', 'genericobject') }}

+

+ {{ __('For optimal performance and reliability, the migration must be performed using the command line:', 'genericobject') }} +

+
+
+ php bin/console migration:genericobject_plugin_to_core + +
+
+ + {{ __('Run this command from your GLPI root directory', 'genericobject') }} + +
+
+
+ +
+
+ +
+

{{ __('Migration Process', 'genericobject') }}

+
    +
  • {{ __('Generic objects will be converted into custom assets', 'genericobject') }}
  • +
  • {{ __('Types will be retained.', 'genericobject') }}
  • +
  • {{ __('Asset data will not be lost', 'genericobject') }}
  • +
+
+ + + {{ __('Note: Migration status detection is based on data presence and may not be 100% accurate. Please verify manually after running the migration command.', 'genericobject') }} + +
+
+
+
+ +
+
+ + {# Next Steps Card #} +
+
+

+ + {{ __('Next Steps', 'genericobject') }} +

+
+
+
+
+ +
+

{{ __('After Migration', 'genericobject') }}

+
    +
  • + + {{ __('Review converted assets in GLPI 11', 'genericobject') }} +
  • +
  • + + {{ __('Test asset access permissions', 'genericobject') }} +
  • +
+
+
+
+ +
+

{{ __('Recommendations', 'genericobject') }}

+
    +
  • + + {{ __('Train users on GLPI 11 native custom assets', 'genericobject') }} +
  • +
  • + + {{ __('Update internal documentation', 'genericobject') }} +
  • +
+
+
+
+
+
+
+
+ +