From 6b61ffce0decbd0e55a7d8757fc79735cb086be3 Mon Sep 17 00:00:00 2001
From: Dawid Parafinski <dawid.parafinski@ibexa.co>
Date: Fri, 20 Dec 2024 09:48:21 +0100
Subject: [PATCH 1/4] Added phpstan

---
 .github/workflows/ci.yaml |  3 +++
 composer.json             |  9 +++++++--
 phpstan-baseline.neon     |  0
 phpstan.neon              | 12 ++++++++++++
 4 files changed, 22 insertions(+), 2 deletions(-)
 create mode 100644 phpstan-baseline.neon
 create mode 100644 phpstan.neon

diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 99c42a2..e02bd2d 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -69,6 +69,9 @@ jobs:
       - name: Run test suite
         run: composer run-script --timeout=600 test
 
+      - name: Run PHPStan analysis
+        run: composer run-script phpstan
+
   integration-tests:
     name: Integration yests
     needs: tests
diff --git a/composer.json b/composer.json
index 7d43def..f39ed11 100644
--- a/composer.json
+++ b/composer.json
@@ -22,13 +22,17 @@
         "ibexa/design-engine": "~4.6.0@dev",
         "ibexa/user": "~4.6.0@dev",
         "ibexa/fieldtype-richtext": "~4.6.0@dev",
+        "ibexa/phpstan": "~4.6.0@dev",
         "ibexa/rest": "~4.6.0@dev",
         "ibexa/search": "~4.6.0@dev",
         "ibexa/test-core": "~4.6.0@dev",
         "ibexa/http-cache": "~4.6.0@dev",
         "ibexa/notifications": "^4.6.x-dev",
         "phpunit/phpunit": "^8.2",
-        "matthiasnoback/symfony-dependency-injection-test": "^4.0"
+        "matthiasnoback/symfony-dependency-injection-test": "^4.0",
+        "phpstan/phpstan": "^2.0",
+        "phpstan/phpstan-phpunit": "^2.0",
+        "phpstan/phpstan-symfony": "^2.0"
     },
     "autoload": {
         "psr-4": {
@@ -55,7 +59,8 @@
         "fix-cs": "php-cs-fixer fix --config=.php-cs-fixer.php -v --show-progress=dots",
         "check-cs": "@fix-cs --dry-run",
         "test": "phpunit -c phpunit.xml",
-        "test-integration": "phpunit -c phpunit.integration.xml"
+        "test-integration": "phpunit -c phpunit.integration.xml",
+        "phpstan": "phpstan analyse"
     },
     "config": {
         "allow-plugins": false
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
new file mode 100644
index 0000000..e69de29
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..737a18b
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,12 @@
+includes:
+    - phpstan-baseline.neon
+    - vendor/phpstan/phpstan-phpunit/extension.neon
+    - vendor/phpstan/phpstan-symfony/extension.neon
+    - vendor/ibexa/phpstan/extension.neon
+
+parameters:
+    level: 8
+    paths:
+        - src
+        - tests
+    treatPhpDocTypesAsCertain: false

From fcf9fb8579481821323af5635351ef6eb5ebe4df Mon Sep 17 00:00:00 2001
From: Dawid Parafinski <dawid.parafinski@ibexa.co>
Date: Mon, 23 Dec 2024 12:06:27 +0100
Subject: [PATCH 2/4] Fixed phpstan issues + baseline

---
 phpstan-baseline.neon                         | 43 +++++++++++++++++++
 phpstan.neon                                  |  3 ++
 src/bundle/Command/SystemInfoDumpCommand.php  |  9 ++--
 .../Controller/SystemInfoController.php       | 10 ++---
 .../Compiler/OutputFormatPass.php             |  2 +-
 .../Compiler/SystemInfoCollectorPass.php      |  7 +--
 .../Compiler/SystemInfoTabGroupPass.php       |  4 +-
 .../IbexaSystemInfoExtension.php              |  7 ++-
 src/bundle/IbexaSystemInfoBundle.php          |  2 +-
 ...rationSymfonyKernelSystemInfoCollector.php |  5 ++-
 .../Collector/EzcPhpSystemInfoCollector.php   |  2 -
 .../Collector/IbexaSystemInfoCollector.php    | 21 +++++----
 .../JsonComposerLockSystemInfoCollector.php   | 39 +++++++----------
 .../ComposerFileValidationException.php       |  2 +-
 .../ComposerLockFileNotFoundException.php     |  2 +-
 .../SystemInfo/EzcSystemInfoWrapper.php       | 36 ++++++----------
 src/bundle/SystemInfo/OutputFormat.php        |  2 +-
 .../OutputFormat/JsonOutputFormat.php         |  6 ++-
 .../SystemInfo/OutputFormatRegistry.php       | 12 ++----
 .../SystemInfo/Value/IbexaSystemInfo.php      |  7 +--
 .../Value/SymfonyKernelSystemInfo.php         |  2 +-
 .../View/Matcher/SystemInfo/Identifier.php    | 22 ++--------
 src/bundle/View/SystemInfoView.php            | 24 ++++-------
 src/bundle/View/SystemInfoViewBuilder.php     | 16 ++++---
 .../Dashboard/EzInfoTwigComponent.php         | 32 ++++++--------
 .../ConfigureMainMenuListener.php             |  6 ++-
 .../SystemInfoTabGroupListener.php            |  8 +---
 src/lib/Value/Stability.php                   |  2 +-
 .../Compiler/SystemInfoTabGroupPassTest.php   |  2 +-
 ...onSymfonyKernelSystemInfoCollectorTest.php |  4 +-
 .../EzcHardwareSystemInfoCollectorTest.php    | 13 +++---
 .../EzcPhpSystemInfoCollectorTest.php         |  4 +-
 ...sonComposerLockSystemInfoCollectorTest.php |  1 -
 .../RepositorySystemInfoCollectorTest.php     |  4 +-
 .../Registry/IdentifierBasedTest.php          | 30 ++++++-------
 .../Matcher/SystemInfo/IdentitifierTest.php   |  6 +--
 .../bundle/View/SystemInfoViewBuilderTest.php | 32 ++++++++------
 .../SystemInfoTabGroupListenerTest.php        | 21 +++------
 .../VersionStabilityCheckerTest.php           |  9 ++++
 39 files changed, 227 insertions(+), 232 deletions(-)

diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index e69de29..ec67bc8 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -0,0 +1,43 @@
+parameters:
+	ignoreErrors:
+		-
+			message: '#^Binary operation "\." between array\|bool\|float\|int\|string\|null and ''/vendor/'' results in an error\.$#'
+			identifier: binaryOp.invalid
+			count: 1
+			path: src/bundle/DependencyInjection/IbexaSystemInfoExtension.php
+
+		-
+			message: '#^Method Ibexa\\Bundle\\SystemInfo\\DependencyInjection\\IbexaSystemInfoExtension\:\:getConfiguration\(\) has parameter \$config with no value type specified in iterable type array\.$#'
+			identifier: missingType.iterableValue
+			count: 1
+			path: src/bundle/DependencyInjection/IbexaSystemInfoExtension.php
+
+		-
+			message: '#^Parameter \#4 \$condition of method Doctrine\\DBAL\\Query\\QueryBuilder\:\:innerJoin\(\) expects string\|null, Doctrine\\DBAL\\Query\\Expression\\CompositeExpression given\.$#'
+			identifier: argument.type
+			count: 1
+			path: src/lib/Storage/Metrics/DraftsCountMetrics.php
+
+		-
+			message: '#^Parameter \#1 \$items of class Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Registry\\IdentifierBased constructor expects array\<Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Collector\\SystemInfoCollector\>, array\<Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Collector\\SystemInfoCollector\|PHPUnit\\Framework\\MockObject\\MockObject\> given\.$#'
+			identifier: argument.type
+			count: 3
+			path: tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
+
+		-
+			message: '#^Method Ibexa\\Tests\\Bundle\\SystemInfo\\View\\SystemInfoViewBuilderTest\:\:getCollectorMock\(\) should return Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Collector\\SystemInfoCollector&PHPUnit\\Framework\\MockObject\\MockObject but returns Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Collector\\SystemInfoCollector\.$#'
+			identifier: return.type
+			count: 1
+			path: tests/bundle/View/SystemInfoViewBuilderTest.php
+
+		-
+			message: '#^Method Ibexa\\Tests\\Bundle\\SystemInfo\\View\\SystemInfoViewBuilderTest\:\:getConfiguratorMock\(\) should return Ibexa\\Core\\MVC\\Symfony\\View\\Configurator&PHPUnit\\Framework\\MockObject\\MockObject but returns Ibexa\\Core\\MVC\\Symfony\\View\\Configurator\.$#'
+			identifier: return.type
+			count: 1
+			path: tests/bundle/View/SystemInfoViewBuilderTest.php
+
+		-
+			message: '#^Method Ibexa\\Tests\\Bundle\\SystemInfo\\View\\SystemInfoViewBuilderTest\:\:getRegistryMock\(\) should return Ibexa\\Bundle\\SystemInfo\\SystemInfo\\SystemInfoCollectorRegistry&PHPUnit\\Framework\\MockObject\\MockObject but returns Ibexa\\Bundle\\SystemInfo\\SystemInfo\\SystemInfoCollectorRegistry\.$#'
+			identifier: return.type
+			count: 1
+			path: tests/bundle/View/SystemInfoViewBuilderTest.php
diff --git a/phpstan.neon b/phpstan.neon
index 737a18b..e0188e8 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -10,3 +10,6 @@ parameters:
         - src
         - tests
     treatPhpDocTypesAsCertain: false
+    ignoreErrors:
+        -
+            message: "#^Cannot call method (fetchOne|fetchColumn|fetchAllAssociative|fetchAssociative|fetchAllKeyValue|fetchFirstColumn)\\(\\) on Doctrine\\\\DBAL\\\\ForwardCompatibility\\\\Result\\|int\\|string\\.$#"
diff --git a/src/bundle/Command/SystemInfoDumpCommand.php b/src/bundle/Command/SystemInfoDumpCommand.php
index 50e2d2e..de3a359 100644
--- a/src/bundle/Command/SystemInfoDumpCommand.php
+++ b/src/bundle/Command/SystemInfoDumpCommand.php
@@ -29,10 +29,7 @@ public function __construct(SystemInfoCollectorRegistry $systemInfoCollectorRegi
         parent::__construct();
     }
 
-    /**
-     * Define command and input options.
-     */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName('ibexa:system-info:dump')
@@ -79,9 +76,9 @@ protected function configure()
     protected function execute(InputInterface $input, OutputInterface $output): int
     {
         if ($input->getOption('list-info-collectors')) {
-            $output->writeln('Available info collectors:', true);
+            $output->writeln('Available info collectors:', OutputInterface::OUTPUT_NORMAL);
             foreach ($this->systemInfoCollectorRegistry->getIdentifiers() as $identifier) {
-                $output->writeln("  $identifier", true);
+                $output->writeln("  $identifier", OutputInterface::OUTPUT_NORMAL);
             }
 
             return Command::SUCCESS;
diff --git a/src/bundle/Controller/SystemInfoController.php b/src/bundle/Controller/SystemInfoController.php
index 2342871..36c3026 100644
--- a/src/bundle/Controller/SystemInfoController.php
+++ b/src/bundle/Controller/SystemInfoController.php
@@ -25,7 +25,7 @@ public function __construct(SystemInfoCollectorRegistry $collectorRegistry)
         $this->collectorRegistry = $collectorRegistry;
     }
 
-    public function performAccessCheck()
+    public function performAccessCheck(): void
     {
         parent::performAccessCheck();
         $this->denyAccessUnlessGranted(new Attribute('setup', 'system_info'));
@@ -43,23 +43,19 @@ public function infoAction(): Response
         ]);
     }
 
-    public function viewInfoAction(SystemInfoView $view)
+    public function viewInfoAction(SystemInfoView $view): SystemInfoView
     {
         return $view;
     }
 
     /**
      * Renders a PHP info page.
-     *
-     * @return \Symfony\Component\HttpFoundation\Response
      */
     public function phpinfoAction(): Response
     {
         ob_start();
         phpinfo();
-        $response = new Response(ob_get_clean());
-
-        return $response;
+        return new Response(ob_get_clean() ?: '');
     }
 }
 
diff --git a/src/bundle/DependencyInjection/Compiler/OutputFormatPass.php b/src/bundle/DependencyInjection/Compiler/OutputFormatPass.php
index ebdf739..16305b1 100644
--- a/src/bundle/DependencyInjection/Compiler/OutputFormatPass.php
+++ b/src/bundle/DependencyInjection/Compiler/OutputFormatPass.php
@@ -18,7 +18,7 @@ class OutputFormatPass implements CompilerPassInterface
      *
      * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
      */
-    public function process(ContainerBuilder $container)
+    public function process(ContainerBuilder $container): void
     {
         if (!$container->has(OutputFormatRegistry::class)) {
             return;
diff --git a/src/bundle/DependencyInjection/Compiler/SystemInfoCollectorPass.php b/src/bundle/DependencyInjection/Compiler/SystemInfoCollectorPass.php
index 53c2783..84a0028 100644
--- a/src/bundle/DependencyInjection/Compiler/SystemInfoCollectorPass.php
+++ b/src/bundle/DependencyInjection/Compiler/SystemInfoCollectorPass.php
@@ -15,12 +15,7 @@
 
 class SystemInfoCollectorPass implements CompilerPassInterface
 {
-    /**
-     * Registers the SystemInfoCollector into the system info collector registry.
-     *
-     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
-     */
-    public function process(ContainerBuilder $container)
+    public function process(ContainerBuilder $container): void
     {
         if (!$container->has(IdentifierBased::class)) {
             return;
diff --git a/src/bundle/DependencyInjection/Compiler/SystemInfoTabGroupPass.php b/src/bundle/DependencyInjection/Compiler/SystemInfoTabGroupPass.php
index dcf70e7..2678e92 100644
--- a/src/bundle/DependencyInjection/Compiler/SystemInfoTabGroupPass.php
+++ b/src/bundle/DependencyInjection/Compiler/SystemInfoTabGroupPass.php
@@ -18,12 +18,10 @@
 class SystemInfoTabGroupPass implements CompilerPassInterface
 {
     /**
-     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
-     *
      * @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
      * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
      */
-    public function process(ContainerBuilder $container)
+    public function process(ContainerBuilder $container): void
     {
         if (!$container->hasDefinition(TabRegistry::class)) {
             return;
diff --git a/src/bundle/DependencyInjection/IbexaSystemInfoExtension.php b/src/bundle/DependencyInjection/IbexaSystemInfoExtension.php
index e8e782f..7f2be65 100644
--- a/src/bundle/DependencyInjection/IbexaSystemInfoExtension.php
+++ b/src/bundle/DependencyInjection/IbexaSystemInfoExtension.php
@@ -29,6 +29,9 @@ public function getAlias()
         return self::EXTENSION_NAME;
     }
 
+    /**
+     * @return \Ibexa\Bundle\SystemInfo\DependencyInjection\Configuration
+     */
     public function getConfiguration(array $config, ContainerBuilder $container)
     {
         return new Configuration();
@@ -37,7 +40,7 @@ public function getConfiguration(array $config, ContainerBuilder $container)
     /**
      * {@inheritdoc}
      */
-    public function load(array $configs, ContainerBuilder $container)
+    public function load(array $configs, ContainerBuilder $container): void
     {
         $loader = new Loader\YamlFileLoader(
             $container,
@@ -61,7 +64,7 @@ public function load(array $configs, ContainerBuilder $container)
         }
     }
 
-    public function prepend(ContainerBuilder $container)
+    public function prepend(ContainerBuilder $container): void
     {
         $this->prependJMSTranslation($container);
     }
diff --git a/src/bundle/IbexaSystemInfoBundle.php b/src/bundle/IbexaSystemInfoBundle.php
index 8bfd90a..d637c98 100644
--- a/src/bundle/IbexaSystemInfoBundle.php
+++ b/src/bundle/IbexaSystemInfoBundle.php
@@ -16,7 +16,7 @@
 
 class IbexaSystemInfoBundle extends Bundle
 {
-    public function build(ContainerBuilder $container)
+    public function build(ContainerBuilder $container): void
     {
         parent::build($container);
         $container->addCompilerPass(new SystemInfoCollectorPass());
diff --git a/src/bundle/SystemInfo/Collector/ConfigurationSymfonyKernelSystemInfoCollector.php b/src/bundle/SystemInfo/Collector/ConfigurationSymfonyKernelSystemInfoCollector.php
index 10c0681..6d5f8c3 100644
--- a/src/bundle/SystemInfo/Collector/ConfigurationSymfonyKernelSystemInfoCollector.php
+++ b/src/bundle/SystemInfo/Collector/ConfigurationSymfonyKernelSystemInfoCollector.php
@@ -32,10 +32,13 @@ class ConfigurationSymfonyKernelSystemInfoCollector implements SystemInfoCollect
      *   'AsseticBundle' => 'Symfony\\Bundle\\AsseticBundle\\AsseticBundle',
      * )
      *
-     * @var array
+     * @var array<string, class-string>
      */
     private $bundles;
 
+    /**
+     * @param array<string, class-string> $bundles
+     */
     public function __construct(Kernel $kernel, array $bundles)
     {
         $this->kernel = $kernel;
diff --git a/src/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollector.php b/src/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollector.php
index c3f6bbb..b1c5e46 100644
--- a/src/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollector.php
+++ b/src/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollector.php
@@ -28,8 +28,6 @@ public function __construct(EzcSystemInfoWrapper $ezcSystemInfo)
      * Collects information about the PHP installation Ibexa DXP is using.
      *  - php version
      *  - php accelerator info.
-     *
-     * @return \Ibexa\Bundle\SystemInfo\SystemInfo\Value\PhpSystemInfo
      */
     public function collect(): PhpSystemInfo
     {
diff --git a/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php b/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php
index 42182b7..02e52ae 100644
--- a/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php
+++ b/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php
@@ -133,7 +133,7 @@ class IbexaSystemInfoCollector implements SystemInfoCollector
     ];
 
     /**
-     * @var \Ibexa\Bundle\SystemInfo\SystemInfo\Value\ComposerSystemInfo|null
+     * @var ComposerSystemInfo|null
      */
     private $composerInfo;
 
@@ -146,7 +146,7 @@ class IbexaSystemInfoCollector implements SystemInfoCollector
     private $kernelProjectDir;
 
     /**
-     * @param \Ibexa\Bundle\SystemInfo\SystemInfo\Collector\JsonComposerLockSystemInfoCollector|\Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector $composerCollector
+     * @param \Ibexa\Bundle\SystemInfo\SystemInfo\Collector\JsonComposerLockSystemInfoCollector|SystemInfoCollector $composerCollector
      * @param bool $debug
      */
     public function __construct(
@@ -155,7 +155,10 @@ public function __construct(
         bool $debug = false
     ) {
         try {
-            $this->composerInfo = $composerCollector->collect();
+            $composerInfo = $composerCollector->collect();
+            if ($composerInfo instanceof ComposerSystemInfo) {
+                $this->composerInfo = $composerInfo;
+            }
         } catch (ComposerLockFileNotFoundException | ComposerFileValidationException $e) {
             // do nothing
         }
@@ -225,9 +228,6 @@ private function extractComposerInfo(IbexaSystemInfo $ibexa): void
         $ibexa->stability = $ibexa->lowestStability = self::getStability($this->composerInfo);
     }
 
-    /**
-     * @throws \Exception
-     */
     private function getEOMDate(string $ibexaRelease): ?DateTime
     {
         return isset(self::EOM[$ibexaRelease]) ?
@@ -235,9 +235,6 @@ private function getEOMDate(string $ibexaRelease): ?DateTime
             null;
     }
 
-    /**
-     * @throws \Exception
-     */
     private function getEOLDate(string $ibexaRelease): ?DateTime
     {
         return isset(self::EOL[$ibexaRelease]) ?
@@ -254,6 +251,9 @@ private static function getStability(ComposerSystemInfo $composerInfo): string
             $stabilityFlags[$composerInfo->minimumStability] :
             $stabilityFlags['stable'];
 
+        if ($composerInfo->packages === null) {
+            return Stability::STABILITIES[$stabilityFlag];
+        }
         // Check if any of the watched packages has lower stability than root
         foreach ($composerInfo->packages as $name => $package) {
             if (!preg_match(self::PACKAGE_WATCH_REGEX, $name)) {
@@ -272,6 +272,9 @@ private static function getStability(ComposerSystemInfo $composerInfo): string
         return Stability::STABILITIES[$stabilityFlag];
     }
 
+    /**
+     * @param list<string> $packageNames
+     */
     private static function hasAnyPackage(
         ComposerSystemInfo $composerInfo,
         array $packageNames
diff --git a/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php b/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php
index b712dde..453f4df 100644
--- a/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php
+++ b/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php
@@ -10,6 +10,7 @@
 use Ibexa\Bundle\SystemInfo\SystemInfo\Exception;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Value\ComposerPackage;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Value\ComposerSystemInfo;
+use Ibexa\Bundle\SystemInfo\SystemInfo\Value\SystemInfo;
 use Ibexa\SystemInfo\Value\Stability;
 use Ibexa\SystemInfo\VersionStability\VersionStabilityChecker;
 
@@ -20,28 +21,21 @@ class JsonComposerLockSystemInfoCollector implements SystemInfoCollector
 {
     public const IBEXA_OSS_PACKAGE = 'ibexa/oss';
 
-    /** @var \Ibexa\SystemInfo\VersionStability\VersionStabilityChecker */
-    private $versionStabilityChecker;
+    private VersionStabilityChecker $versionStabilityChecker;
 
-    /**
-     * @var string Composer lock file with full path.
-     */
-    private $lockFile;
+    private string $lockFile;
 
-    /**
-     * @var string Composer json file with full path.
-     */
-    private $jsonFile;
+    private string $jsonFile;
 
     /**
-     * @var \Ibexa\Bundle\SystemInfo\SystemInfo\Value\ComposerSystemInfo The collected value, cached in case info is collected by other collectors.
+     * The collected value, cached in case info is collected by other collectors.
      */
-    private $value;
+    private ?ComposerSystemInfo $value = null;
 
     public function __construct(
         VersionStabilityChecker $versionStabilityChecker,
-        $lockFile,
-        $jsonFile
+        string $lockFile,
+        string $jsonFile
     ) {
         $this->versionStabilityChecker = $versionStabilityChecker;
         $this->lockFile = $lockFile;
@@ -51,13 +45,9 @@ public function __construct(
     /**
      * Collects information about installed composer packages.
      *
-     * @return \Ibexa\Bundle\SystemInfo\SystemInfo\Value\ComposerSystemInfo
-     *
      * @throws Exception\ComposerLockFileNotFoundException if the composer.lock file was not found.
      * @throws Exception\ComposerJsonFileNotFoundException if the composer.json file was not found.
      * @throws Exception\ComposerFileValidationException if composer.lock of composer.json are not valid.
-     *
-     * @return \Ibexa\Bundle\SystemInfo\SystemInfo\Value\ComposerSystemInfo
      */
     public function collect(): ComposerSystemInfo
     {
@@ -73,8 +63,8 @@ public function collect(): ComposerSystemInfo
             throw new Exception\ComposerJsonFileNotFoundException($this->jsonFile);
         }
 
-        $lockData = json_decode(file_get_contents($this->lockFile), true);
-        $jsonData = json_decode(file_get_contents($this->jsonFile), true);
+        $lockData = json_decode(file_get_contents($this->lockFile) ?: '', true);
+        $jsonData = json_decode(file_get_contents($this->jsonFile) ?: '', true);
 
         if (!is_array($lockData)) {
             throw new Exception\ComposerFileValidationException($this->lockFile);
@@ -86,7 +76,7 @@ public function collect(): ComposerSystemInfo
 
         $stability = InstalledVersions::isInstalled(self::IBEXA_OSS_PACKAGE)
             ? $this->versionStabilityChecker->getStability(
-                InstalledVersions::getVersion(self::IBEXA_OSS_PACKAGE)
+                InstalledVersions::getVersion(self::IBEXA_OSS_PACKAGE) ?? ''
             )
             : $this->getMinimumStability($lockData);
 
@@ -98,7 +88,7 @@ public function collect(): ComposerSystemInfo
     }
 
     /**
-     * @param array $lockData
+     * @param array<string, mixed> $lockData
      *
      * @return \Ibexa\Bundle\SystemInfo\SystemInfo\Value\ComposerPackage[]
      */
@@ -145,7 +135,7 @@ private function extractPackages(array $lockData): array
     }
 
     /**
-     * @param array $jsonData
+     * @param array<string, mixed> $jsonData
      *
      * @return string[]
      */
@@ -189,6 +179,9 @@ private static function setNormalizedVersion(ComposerPackage $package): void
         $package->version = $version;
     }
 
+    /**
+     * @param array<string, mixed> $lockData
+     */
     private function getMinimumStability(array $lockData): ?string
     {
         return $lockData['minimum-stability'] ?? null;
diff --git a/src/bundle/SystemInfo/Exception/ComposerFileValidationException.php b/src/bundle/SystemInfo/Exception/ComposerFileValidationException.php
index 79613bb..6eb38f4 100644
--- a/src/bundle/SystemInfo/Exception/ComposerFileValidationException.php
+++ b/src/bundle/SystemInfo/Exception/ComposerFileValidationException.php
@@ -10,7 +10,7 @@
 
 final class ComposerFileValidationException extends Exception implements SystemInfoException
 {
-    public function __construct(string $path, $code = 0, Exception $previous = null)
+    public function __construct(string $path, int $code = 0, Exception $previous = null)
     {
         $message = sprintf('Composer file %s is not valid.', $path);
 
diff --git a/src/bundle/SystemInfo/Exception/ComposerLockFileNotFoundException.php b/src/bundle/SystemInfo/Exception/ComposerLockFileNotFoundException.php
index f90b4d0..0e0db84 100644
--- a/src/bundle/SystemInfo/Exception/ComposerLockFileNotFoundException.php
+++ b/src/bundle/SystemInfo/Exception/ComposerLockFileNotFoundException.php
@@ -11,7 +11,7 @@
 
 class ComposerLockFileNotFoundException extends BaseNotFoundException implements SystemInfoException
 {
-    public function __construct($path, Exception $previous = null)
+    public function __construct(string $path, Exception $previous = null)
     {
         parent::__construct('composer.lock file', $path, $previous);
     }
diff --git a/src/bundle/SystemInfo/EzcSystemInfoWrapper.php b/src/bundle/SystemInfo/EzcSystemInfoWrapper.php
index 39e2e67..9dd5348 100644
--- a/src/bundle/SystemInfo/EzcSystemInfoWrapper.php
+++ b/src/bundle/SystemInfo/EzcSystemInfoWrapper.php
@@ -7,6 +7,7 @@
 namespace Ibexa\Bundle\SystemInfo\SystemInfo;
 
 use ezcSystemInfo;
+use ezcSystemInfoAccelerator;
 use ezcSystemInfoReaderCantScanOSException;
 
 /**
@@ -15,41 +16,30 @@
  */
 class EzcSystemInfoWrapper
 {
-    /** @var string */
-    public $osType;
+    public string $osType;
 
-    /** @var string */
-    public $osName;
+    public string $osName;
 
-    /** @var string */
-    public $fileSystemType;
+    public string $fileSystemType;
 
-    /** @var int */
-    public $cpuCount;
+    public int $cpuCount;
 
-    /** @var string */
-    public $cpuType;
+    public string $cpuType;
 
-    /** @var float */
-    public $cpuSpeed;
+    public float $cpuSpeed;
 
     /** @var int */
-    public $memorySize;
+    public int $memorySize;
 
-    /** @var string */
-    public $lineSeparator;
+    public string $lineSeparator;
 
-    /** @var string */
-    public $backupFileName;
+    public string $backupFileName;
 
-    /** @var array */
-    public $phpVersion;
+    public string $phpVersion;
 
-    /** @var \ezcSystemInfoAccelerator */
-    public $phpAccelerator;
+    public ezcSystemInfoAccelerator $phpAccelerator;
 
-    /** @var bool */
-    public $isShellExecution;
+    public bool $isShellExecution;
 
     public function __construct()
     {
diff --git a/src/bundle/SystemInfo/OutputFormat.php b/src/bundle/SystemInfo/OutputFormat.php
index 81d34e8..91aa466 100644
--- a/src/bundle/SystemInfo/OutputFormat.php
+++ b/src/bundle/SystemInfo/OutputFormat.php
@@ -11,7 +11,7 @@ interface OutputFormat
     /**
      * Format an array of collected information data, and return it as string.
      *
-     * @param array $collectedInfo
+     * @param array<string, \Ibexa\Bundle\SystemInfo\SystemInfo\Value\SystemInfo> $collectedInfo
      *
      * @return string
      */
diff --git a/src/bundle/SystemInfo/OutputFormat/JsonOutputFormat.php b/src/bundle/SystemInfo/OutputFormat/JsonOutputFormat.php
index 6d5328d..4c4f75a 100644
--- a/src/bundle/SystemInfo/OutputFormat/JsonOutputFormat.php
+++ b/src/bundle/SystemInfo/OutputFormat/JsonOutputFormat.php
@@ -15,7 +15,11 @@ class JsonOutputFormat implements SystemInfoOutputFormat
 {
     public function format(array $collectedInfo)
     {
-        return json_encode($collectedInfo, JSON_PRETTY_PRINT);
+        $json = json_encode($collectedInfo, JSON_PRETTY_PRINT);
+        if ($json === false) {
+            return '';
+        }
+        return $json;
     }
 }
 
diff --git a/src/bundle/SystemInfo/OutputFormatRegistry.php b/src/bundle/SystemInfo/OutputFormatRegistry.php
index c076e8e..3292a3f 100644
--- a/src/bundle/SystemInfo/OutputFormatRegistry.php
+++ b/src/bundle/SystemInfo/OutputFormatRegistry.php
@@ -14,7 +14,7 @@
 class OutputFormatRegistry
 {
     /** @var \Ibexa\Bundle\SystemInfo\SystemInfo\OutputFormat[] */
-    private $registry = [];
+    private array $registry = [];
 
     /**
      * @param \Ibexa\Bundle\SystemInfo\SystemInfo\OutputFormat[] $items Hash of OutputFormats, with identifier string as key.
@@ -25,15 +25,9 @@ public function __construct(array $items = [])
     }
 
     /**
-     * Returns the OutputFormat matching the argument.
-     *
-     * @param string $identifier An identifier string.
-     *
      * @throws \Ibexa\Core\Base\Exceptions\NotFoundException If no OutputFormat exists with this identifier
-     *
-     * @return \Ibexa\Bundle\SystemInfo\SystemInfo\Collector\OutputFormat The OutputFormat given by the identifier.
      */
-    public function getItem($identifier)
+    public function getItem(string $identifier): OutputFormat
     {
         if (isset($this->registry[$identifier])) {
             return $this->registry[$identifier];
@@ -47,7 +41,7 @@ public function getItem($identifier)
      *
      * @return string[] Array of identifier strings.
      */
-    public function getIdentifiers()
+    public function getIdentifiers(): array
     {
         return array_keys($this->registry);
     }
diff --git a/src/bundle/SystemInfo/Value/IbexaSystemInfo.php b/src/bundle/SystemInfo/Value/IbexaSystemInfo.php
index 4373d80..3017853 100644
--- a/src/bundle/SystemInfo/Value/IbexaSystemInfo.php
+++ b/src/bundle/SystemInfo/Value/IbexaSystemInfo.php
@@ -6,6 +6,7 @@
  */
 namespace Ibexa\Bundle\SystemInfo\SystemInfo\Value;
 
+use DateTime;
 use Ibexa\Contracts\Core\Repository\Values\ValueObject;
 
 /**
@@ -59,7 +60,7 @@ class IbexaSystemInfo extends ValueObject implements SystemInfo
      *
      * @see https://support.ibexa.co/Public/Service-Life
      */
-    public $endOfMaintenanceDate;
+    public ?DateTime $endOfMaintenanceDate;
 
     /**
      * @var bool
@@ -73,7 +74,7 @@ class IbexaSystemInfo extends ValueObject implements SystemInfo
      *
      * @see https://support.ibexa.co/Public/Service-Life
      */
-    public $endOfLifeDate;
+    public ?DateTime $endOfLifeDate;
 
     /**
      * @var bool
@@ -104,7 +105,7 @@ class IbexaSystemInfo extends ValueObject implements SystemInfo
     /**
      * @deprecated This was duplication of collected info from Composer, now only contains key 'minimumStability'
      *
-     * @var array|null
+     * @var array<string, mixed>|null
      */
     public $composerInfo;
 }
diff --git a/src/bundle/SystemInfo/Value/SymfonyKernelSystemInfo.php b/src/bundle/SystemInfo/Value/SymfonyKernelSystemInfo.php
index 21c5561..f2416bd 100644
--- a/src/bundle/SystemInfo/Value/SymfonyKernelSystemInfo.php
+++ b/src/bundle/SystemInfo/Value/SymfonyKernelSystemInfo.php
@@ -49,7 +49,7 @@ class SymfonyKernelSystemInfo extends ValueObject implements SystemInfo
      *   'AsseticBundle' => 'Symfony\\Bundle\\AsseticBundle\\AsseticBundle',
      * )
      *
-     * @var array
+     * @var array<string, class-string>
      */
     public $bundles;
 
diff --git a/src/bundle/View/Matcher/SystemInfo/Identifier.php b/src/bundle/View/Matcher/SystemInfo/Identifier.php
index 2e92edc..5ca1c85 100644
--- a/src/bundle/View/Matcher/SystemInfo/Identifier.php
+++ b/src/bundle/View/Matcher/SystemInfo/Identifier.php
@@ -14,32 +14,18 @@ class Identifier implements ViewMatcherInterface
 {
     /**
      * Matched SystemInfo identifier. Example: 'php', 'hardware'...
-     *
-     * @var string
      */
-    private $identifier;
+    private string $identifier;
 
-    /**
-     * Registers the matching configuration for the matcher.
-     * It's up to the implementor to validate $matchingConfig since it can be anything configured by the end-developer.
-     *
-     * @param mixed $matchingConfig
-     *
-     * @throws \InvalidArgumentException Should be thrown if $matchingConfig is not valid.
-     */
-    public function setMatchingConfig($matchingConfig)
+    public function setMatchingConfig($matchingConfig): void
     {
         $this->identifier = $matchingConfig;
     }
 
     /**
      * Matches the $view against a set of matchers.
-     *
-     * @param \Ibexa\Bundle\SystemInfo\View\SystemInfoView $view
-     *
-     * @return bool
      */
-    public function match(View $view)
+    public function match(View $view): bool
     {
         if (!$view instanceof SystemInfoView) {
             return false;
@@ -48,7 +34,7 @@ public function match(View $view)
         return $this->toIdentifier($view->getInfo()) === $this->identifier;
     }
 
-    private function toIdentifier($object)
+    private function toIdentifier(object $object): string
     {
         $className = \get_class($object);
         $className = substr($className, strrpos($className, '\\') + 1);
diff --git a/src/bundle/View/SystemInfoView.php b/src/bundle/View/SystemInfoView.php
index 31a7ab2..d5c1095 100644
--- a/src/bundle/View/SystemInfoView.php
+++ b/src/bundle/View/SystemInfoView.php
@@ -6,37 +6,29 @@
  */
 namespace Ibexa\Bundle\SystemInfo\View;
 
+use Ibexa\Bundle\SystemInfo\SystemInfo\Value\SystemInfo;
 use Ibexa\Core\MVC\Symfony\View\BaseView;
 use Ibexa\Core\MVC\Symfony\View\View;
 
 class SystemInfoView extends BaseView implements View
 {
-    /**
-     * @var \Ibexa\Bundle\SystemInfo\SystemInfo\Value\SystemInfo
-     */
-    private $info;
+    private SystemInfo $info;
 
-    /**
-     * @param \Ibexa\Bundle\SystemInfo\SystemInfo\Value\SystemInfo $info
-     *
-     * @return SystemInfoView
-     */
-    public function setInfo($info)
+    public function setInfo(SystemInfo $info): self
     {
         $this->info = $info;
 
         return $this;
     }
-
-    /**
-     * @return \Ibexa\Bundle\SystemInfo\SystemInfo\Value\SystemInfo
-     */
-    public function getInfo()
+    public function getInfo(): SystemInfo
     {
         return $this->info;
     }
 
-    protected function getInternalParameters()
+    /**
+     * @return array{info: \Ibexa\Bundle\SystemInfo\SystemInfo\Value\SystemInfo}
+     */
+    protected function getInternalParameters(): array
     {
         return ['info' => $this->info];
     }
diff --git a/src/bundle/View/SystemInfoViewBuilder.php b/src/bundle/View/SystemInfoViewBuilder.php
index 4487dbd..4f680f6 100644
--- a/src/bundle/View/SystemInfoViewBuilder.php
+++ b/src/bundle/View/SystemInfoViewBuilder.php
@@ -6,11 +6,14 @@
  */
 namespace Ibexa\Bundle\SystemInfo\View;
 
+use Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Exception\SystemInfoException;
 use Ibexa\Bundle\SystemInfo\SystemInfo\SystemInfoCollectorRegistry;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Value\InvalidSystemInfo;
+use Ibexa\Core\MVC\Symfony\View\BaseView;
 use Ibexa\Core\MVC\Symfony\View\Builder\ViewBuilder;
 use Ibexa\Core\MVC\Symfony\View\Configurator;
+use Ibexa\Core\MVC\Symfony\View\View;
 
 class SystemInfoViewBuilder implements ViewBuilder
 {
@@ -32,12 +35,17 @@ public function __construct(Configurator $viewConfigurator, SystemInfoCollectorR
         $this->registry = $registry;
     }
 
-    public function matches($argument)
+    public function matches($argument): bool
     {
         return $argument === 'ibexa.support_tools.view.controller:viewInfoAction';
     }
 
-    public function buildView(array $parameters)
+    /**
+     * @param array<string, string> $parameters
+     *
+     * @return \Ibexa\Bundle\SystemInfo\View\SystemInfoView
+     */
+    public function buildView(array $parameters): View
     {
         $collector = $this->getCollector($parameters['systemInfoIdentifier']);
         $view = new SystemInfoView(null, [], $parameters['viewType']);
@@ -57,10 +65,8 @@ public function buildView(array $parameters)
 
     /**
      * @param string $identifier A SystemInfo collector identifier (php, hardware...)
-     *
-     * @return \Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector
      */
-    private function getCollector($identifier)
+    private function getCollector(string $identifier): SystemInfoCollector
     {
         return $this->registry->getItem($identifier);
     }
diff --git a/src/lib/Component/Dashboard/EzInfoTwigComponent.php b/src/lib/Component/Dashboard/EzInfoTwigComponent.php
index fd9e4cb..ddb5ce9 100644
--- a/src/lib/Component/Dashboard/EzInfoTwigComponent.php
+++ b/src/lib/Component/Dashboard/EzInfoTwigComponent.php
@@ -14,27 +14,21 @@
 
 class EzInfoTwigComponent implements Renderable
 {
-    /** @var string */
-    protected $template;
+    protected string $template;
 
-    /** @var \Twig\Environment */
-    protected $twig;
+    protected Environment $twig;
 
-    /** @var array */
-    protected $parameters;
+    /** @var array<string, mixed> */
+    protected array $parameters;
 
-    /** @var \Ibexa\Bundle\SystemInfo\SystemInfo\Value\IbexaSystemInfo */
-    private $ibexaSystemInfo;
+    private IbexaSystemInfo $ibexaSystemInfo;
 
-    /** @var array */
-    private $urlList;
+    /** @var array<string, string>  */
+    private array $urlList;
 
     /**
-     * @param \Twig\Environment $twig
-     * @param string $template
-     * @param \Ibexa\Bundle\SystemInfo\SystemInfo\Value\IbexaSystemInfo $ibexaSystemInfo
-     * @param array $urlList
-     * @param array $parameters
+     * @param array<string, string> $urlList
+     * @param array<string, mixed>  $parameters
      */
     public function __construct(
         Environment $twig,
@@ -51,9 +45,7 @@ public function __construct(
     }
 
     /**
-     * @param array $parameters
-     *
-     * @return string
+     * @param array<string, mixed> $parameters
      */
     public function render(array $parameters = []): string
     {
@@ -66,13 +58,13 @@ public function render(array $parameters = []): string
     }
 
     /**
-     * @return array
+     * @return array<string, string>
      */
     private function replaceUrlPlaceholders(): array
     {
         $urls = $this->urlList;
         foreach ($this->urlList as $urlName => $url) {
-            foreach ($this->ibexaSystemInfo as $attribute => $value) {
+            foreach (get_object_vars($this->ibexaSystemInfo) as $attribute => $value) {
                 if (\is_string($value) && \strpos($url, '{ez.' . $attribute . '}') !== false) {
                     $urls[$urlName] = \str_replace('{ez.' . $attribute . '}', $value, $url);
                 }
diff --git a/src/lib/EventListener/ConfigureMainMenuListener.php b/src/lib/EventListener/ConfigureMainMenuListener.php
index e6494d7..bf92e61 100644
--- a/src/lib/EventListener/ConfigureMainMenuListener.php
+++ b/src/lib/EventListener/ConfigureMainMenuListener.php
@@ -45,7 +45,11 @@ public function onMenuConfigure(ConfigureMenuEvent $event): void
             return;
         }
 
-        $menu->getChild(MainMenuBuilder::ITEM_ADMIN)->addChild(
+        $adminMenu = $menu->getChild(MainMenuBuilder::ITEM_ADMIN);
+        if ($adminMenu === null) {
+            return;
+        }
+        $adminMenu->addChild(
             $this->menuItemFactory->createItem(
                 self::ITEM_ADMIN__SYSTEMINFO,
                 [
diff --git a/src/lib/EventListener/SystemInfoTabGroupListener.php b/src/lib/EventListener/SystemInfoTabGroupListener.php
index cb0732d..d735141 100644
--- a/src/lib/EventListener/SystemInfoTabGroupListener.php
+++ b/src/lib/EventListener/SystemInfoTabGroupListener.php
@@ -39,9 +39,6 @@ public function __construct(
         $this->systeminfoCollectorRegistry = $systeminfoCollectorRegistry;
     }
 
-    /**
-     * @return array
-     */
     public static function getSubscribedEvents(): array
     {
         return [
@@ -49,10 +46,7 @@ public static function getSubscribedEvents(): array
         ];
     }
 
-    /**
-     * @param \Ibexa\AdminUi\Tab\Event\TabGroupEvent $event
-     */
-    public function onTabGroupPreRender(TabGroupEvent $event)
+    public function onTabGroupPreRender(TabGroupEvent $event): void
     {
         $tabGroup = $event->getData();
 
diff --git a/src/lib/Value/Stability.php b/src/lib/Value/Stability.php
index c63ee8b..a6175c4 100644
--- a/src/lib/Value/Stability.php
+++ b/src/lib/Value/Stability.php
@@ -11,7 +11,7 @@
 final class Stability
 {
     /**
-     * @var array Hash of stability constant values to human readable stabilities, see Composer\Package\BasePackage.
+     * @var array<int, string> Hash of stability constant values to human readable stabilities, see Composer\Package\BasePackage.
      *
      * Needed as long as we don't want to depend on Composer.
      */
diff --git a/tests/bundle/DependencyInjection/Compiler/SystemInfoTabGroupPassTest.php b/tests/bundle/DependencyInjection/Compiler/SystemInfoTabGroupPassTest.php
index bdeac1d..f5463a4 100644
--- a/tests/bundle/DependencyInjection/Compiler/SystemInfoTabGroupPassTest.php
+++ b/tests/bundle/DependencyInjection/Compiler/SystemInfoTabGroupPassTest.php
@@ -31,7 +31,7 @@ protected function registerCompilerPass(ContainerBuilder $container): void
         $container->addCompilerPass(new SystemInfoTabGroupPass());
     }
 
-    public function testProcess()
+    public function testProcess(): void
     {
         $tabGroupDefinition = new Definition(TabGroup::class, ['systeminfo']);
 
diff --git a/tests/bundle/SystemInfo/Collector/ConfigurationSymfonyKernelSystemInfoCollectorTest.php b/tests/bundle/SystemInfo/Collector/ConfigurationSymfonyKernelSystemInfoCollectorTest.php
index 92768e5..4dd73b7 100644
--- a/tests/bundle/SystemInfo/Collector/ConfigurationSymfonyKernelSystemInfoCollectorTest.php
+++ b/tests/bundle/SystemInfo/Collector/ConfigurationSymfonyKernelSystemInfoCollectorTest.php
@@ -16,7 +16,7 @@ class ConfigurationSymfonyKernelSystemInfoCollectorTest extends TestCase
     /**
      * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Collector\ConfigurationSymfonyKernelSystemInfoCollector::collect()
      */
-    public function testCollect()
+    public function testCollect(): void
     {
         $expected = new SymfonyKernelSystemInfo([
             'environment' => 'dev',
@@ -75,8 +75,6 @@ public function testCollect()
 
         $value = $symfonyCollector->collect();
 
-        self::assertInstanceOf('Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Value\\SymfonyKernelSystemInfo', $value);
-
         self::assertEquals($expected, $value);
     }
 }
diff --git a/tests/bundle/SystemInfo/Collector/EzcHardwareSystemInfoCollectorTest.php b/tests/bundle/SystemInfo/Collector/EzcHardwareSystemInfoCollectorTest.php
index ac3247a..17a677c 100644
--- a/tests/bundle/SystemInfo/Collector/EzcHardwareSystemInfoCollectorTest.php
+++ b/tests/bundle/SystemInfo/Collector/EzcHardwareSystemInfoCollectorTest.php
@@ -7,6 +7,7 @@
 namespace Ibexa\Tests\Bundle\SystemInfo\SystemInfo\Collector;
 
 use Ibexa\Bundle\SystemInfo\SystemInfo\Collector\EzcHardwareSystemInfoCollector;
+use Ibexa\Bundle\SystemInfo\SystemInfo\EzcSystemInfoWrapper;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Value\HardwareSystemInfo;
 use PHPUnit\Framework\TestCase;
 
@@ -25,13 +26,13 @@ class EzcHardwareSystemInfoCollectorTest extends TestCase
     protected function setUp(): void
     {
         $this->ezcSystemInfoMock = $this
-            ->getMockBuilder('Ibexa\\Bundle\\SystemInfo\\SystemInfo\\EzcSystemInfoWrapper')
+            ->getMockBuilder(EzcSystemInfoWrapper::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->ezcSystemInfoMock->cpuType = 'Intel(R) Core(TM) i7-3720QM CPU @ 2.60GHz';
-        $this->ezcSystemInfoMock->cpuSpeed = '2591.9000000000001';
-        $this->ezcSystemInfoMock->cpuCount = '1';
-        $this->ezcSystemInfoMock->memorySize = '1554632704';
+        $this->ezcSystemInfoMock->cpuSpeed = 2591.9000000000001;
+        $this->ezcSystemInfoMock->cpuCount = 1;
+        $this->ezcSystemInfoMock->memorySize = 1554632704;
 
         $this->ezcHardware = new EzcHardwareSystemInfoCollector($this->ezcSystemInfoMock);
     }
@@ -39,11 +40,11 @@ protected function setUp(): void
     /**
      * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Collector\EzcHardwareSystemInfoCollector::collect()
      */
-    public function testCollect()
+    public function testCollect(): void
     {
         $value = $this->ezcHardware->collect();
 
-        self::assertInstanceOf('Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Value\\HardwareSystemInfo', $value);
+        self::assertInstanceOf(HardwareSystemInfo::class, $value);
 
         self::assertEquals(
             new HardwareSystemInfo([
diff --git a/tests/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollectorTest.php b/tests/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollectorTest.php
index 1d38a07..b0c44b5 100644
--- a/tests/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollectorTest.php
+++ b/tests/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollectorTest.php
@@ -49,11 +49,11 @@ protected function setUp(): void
     /**
      * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Collector\EzcPhpSystemInfoCollector::collect()
      */
-    public function testCollect()
+    public function testCollect(): void
     {
         $value = $this->ezcPhpCollector->collect();
 
-        self::assertInstanceOf('Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Value\\PhpSystemInfo', $value);
+        self::assertInstanceOf(PhpSystemInfo::class, $value);
 
         self::assertEquals(
             new PhpSystemInfo([
diff --git a/tests/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollectorTest.php b/tests/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollectorTest.php
index 3f1b47d..053ef5e 100644
--- a/tests/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollectorTest.php
+++ b/tests/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollectorTest.php
@@ -85,7 +85,6 @@ public function testCollectWithMinimumStability(): void
         );
         $value = $composerCollector->collect();
 
-        self::assertInstanceOf('Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Value\\ComposerSystemInfo', $value);
         self::assertEquals($expected, $value);
     }
 
diff --git a/tests/bundle/SystemInfo/Collector/RepositorySystemInfoCollectorTest.php b/tests/bundle/SystemInfo/Collector/RepositorySystemInfoCollectorTest.php
index 10be262..f8978e8 100644
--- a/tests/bundle/SystemInfo/Collector/RepositorySystemInfoCollectorTest.php
+++ b/tests/bundle/SystemInfo/Collector/RepositorySystemInfoCollectorTest.php
@@ -23,7 +23,7 @@ class RepositorySystemInfoCollectorTest extends TestCase
     private $dbalConnectionMock;
 
     /**
-     * @var \Doctrine\DBAL\Platforms\MySqlPlatform|\PHPUnit\Framework\MockObject\MockObject
+     * @var \Doctrine\DBAL\Platforms\AbstractPlatform & \PHPUnit\Framework\MockObject\MockObject
      */
     private $dbalPlatformMock;
 
@@ -58,7 +58,7 @@ protected function setUp(): void
     /**
      * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Collector\RepositorySystemInfoCollector::collect()
      */
-    public function testCollect()
+    public function testCollect(): void
     {
         $expected = new RepositorySystemInfo([
             'type' => 'mysql',
diff --git a/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php b/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
index ecb9387..7a853bd 100644
--- a/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
+++ b/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
@@ -6,27 +6,25 @@
  */
 namespace Ibexa\Tests\Bundle\SystemInfo\SystemInfo\Registry;
 
+use Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Registry\IdentifierBased;
 use Ibexa\Core\Base\Exceptions\NotFoundException;
 use PHPUnit\Framework\TestCase;
 
 class IdentifierBasedTest extends TestCase
 {
-    /**
-     * @var \Ibexa\Bundle\SystemInfo\SystemInfo\Registry\IdentifierBasedEzcPhpSystemInfoCollector
-     */
-    private $registry;
+    private IdentifierBased $registry;
 
     /**
-     * @var \PHPUnit\Framework\MockObject\MockObject[]|\Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector[]
+     * @var \PHPUnit\Framework\MockObject\MockObject[]|SystemInfoCollector[]
      */
-    private $testItems;
+    private array $testItems;
 
     protected function setUp(): void
     {
         $this->testItems = [
-            'foo' => $this->createMock('Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Collector\\SystemInfoCollector'),
-            'bar' => $this->createMock('Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Collector\\SystemInfoCollector'),
+            'foo' => $this->createMock(SystemInfoCollector::class),
+            'bar' => $this->createMock(SystemInfoCollector::class),
         ];
 
         $this->registry = new IdentifierBased();
@@ -35,9 +33,9 @@ protected function setUp(): void
     /**
      * Test adding items to the registry, and getting items from it.
      *
-     * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Registry\IdentifierBased::getItem()
+     * @covers IdentifierBased::getItem
      */
-    public function testAddAndGetItems()
+    public function testAddAndGetItems(): void
     {
         $this->registry = new IdentifierBased($this->testItems);
 
@@ -48,9 +46,9 @@ public function testAddAndGetItems()
     /**
      * Test exception when registry item is not found.
      *
-     * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Registry\IdentifierBased::getItem()
+     * @covers IdentifierBased::getItem
      */
-    public function testGetItemNotFound()
+    public function testGetItemNotFound(): void
     {
         $this->expectException(NotFoundException::class);
         $this->registry->getItem('notfound');
@@ -59,9 +57,9 @@ public function testGetItemNotFound()
     /**
      * Test replacing an item in the registry.
      *
-     * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Registry\IdentifierBased::getItem()
+     * @covers IdentifierBased::getItem
      */
-    public function testReplaceItem()
+    public function testReplaceItem(): void
     {
         $this->registry = new IdentifierBased($this->testItems);
 
@@ -78,10 +76,10 @@ public function testReplaceItem()
     /**
      * Test getting all registered identifiers.
      *
-     * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Registry\IdentifierBased::getIdentifiers()
+     * @covers IdentifierBased::getIdentifiers
      * @depends testAddAndGetItems
      */
-    public function testGetIdentifiers()
+    public function testGetIdentifiers(): void
     {
         $this->registry = new IdentifierBased($this->testItems);
 
diff --git a/tests/bundle/View/Matcher/SystemInfo/IdentitifierTest.php b/tests/bundle/View/Matcher/SystemInfo/IdentitifierTest.php
index af99578..8d28add 100644
--- a/tests/bundle/View/Matcher/SystemInfo/IdentitifierTest.php
+++ b/tests/bundle/View/Matcher/SystemInfo/IdentitifierTest.php
@@ -14,7 +14,7 @@
 
 class IdentitifierTest extends TestCase
 {
-    public function testMatch()
+    public function testMatch(): void
     {
         $view = new SystemInfoView();
         $view->setInfo(new HardwareSystemInfo());
@@ -25,7 +25,7 @@ public function testMatch()
         self::assertTrue($matcher->match($view));
     }
 
-    public function testNoMatch()
+    public function testNoMatch(): void
     {
         $view = new SystemInfoView();
         $view->setInfo(new HardwareSystemInfo());
@@ -36,7 +36,7 @@ public function testNoMatch()
         self::assertFalse($matcher->match($view));
     }
 
-    public function testMatchOtherView()
+    public function testMatchOtherView(): void
     {
         $view = new ContentView();
 
diff --git a/tests/bundle/View/SystemInfoViewBuilderTest.php b/tests/bundle/View/SystemInfoViewBuilderTest.php
index a603d81..9ea05ca 100644
--- a/tests/bundle/View/SystemInfoViewBuilderTest.php
+++ b/tests/bundle/View/SystemInfoViewBuilderTest.php
@@ -6,31 +6,34 @@
  */
 namespace Ibexa\Tests\Bundle\SystemInfo\View;
 
+use Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector;
+use Ibexa\Bundle\SystemInfo\SystemInfo\SystemInfoCollectorRegistry;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Value\SystemInfo;
 use Ibexa\Bundle\SystemInfo\View\SystemInfoViewBuilder;
+use Ibexa\Core\MVC\Symfony\View\Configurator;
 use PHPUnit\Framework\TestCase;
 
 class SystemInfoViewBuilderTest extends TestCase
 {
-    private $configuratorMock;
+    private Configurator $configuratorMock;
 
-    private $registryMock;
+    private SystemInfoCollectorRegistry $registryMock;
 
-    private $collectorMock;
+    private SystemInfoCollector $collectorMock;
 
-    public function testMatches()
+    public function testMatches(): void
     {
         $builder = new SystemInfoViewBuilder($this->getConfiguratorMock(), $this->getRegistryMock());
         self::assertTrue($builder->matches('ibexa.support_tools.view.controller:viewInfoAction'));
     }
 
-    public function testNotMatches()
+    public function testNotMatches(): void
     {
         $builder = new SystemInfoViewBuilder($this->getConfiguratorMock(), $this->getRegistryMock());
         self::assertFalse($builder->matches('service:someAction'));
     }
 
-    public function testBuildView()
+    public function testBuildView(): void
     {
         $builder = new SystemInfoViewBuilder(
             $this->getConfiguratorMock(),
@@ -54,24 +57,25 @@ public function testBuildView()
     }
 
     /**
-     * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Core\MVC\Symfony\View\Configurator
+     * @return \PHPUnit\Framework\MockObject\MockObject & \Ibexa\Core\MVC\Symfony\View\Configurator
      */
-    protected function getConfiguratorMock()
+    protected function getConfiguratorMock(): Configurator
     {
         if (!isset($this->configuratorMock)) {
-            $this->configuratorMock = $this->createMock('Ibexa\\Core\\MVC\\Symfony\\View\\Configurator');
+            $this->configuratorMock = $this->createMock(Configurator::class);
         }
 
         return $this->configuratorMock;
     }
 
     /**
-     * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Bundle\SystemInfo\SystemInfo\SystemInfoCollectorRegistry
+     * @return \PHPUnit\Framework\MockObject\MockObject & \Ibexa\Bundle\SystemInfo\SystemInfo\SystemInfoCollectorRegistry
      */
-    protected function getRegistryMock()
+    protected function getRegistryMock(): SystemInfoCollectorRegistry
     {
         if (!isset($this->registryMock)) {
-            $this->registryMock = $this->createMock('Ibexa\\Bundle\\SystemInfo\\SystemInfo\\SystemInfoCollectorRegistry');
+            $this->registryMock = $this->createMock(SystemInfoCollectorRegistry::class
+            );
         }
 
         return $this->registryMock;
@@ -80,10 +84,10 @@ protected function getRegistryMock()
     /**
      * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector
      */
-    protected function getCollectorMock()
+    protected function getCollectorMock(): SystemInfoCollector
     {
         if (!isset($this->collectorMock)) {
-            $this->collectorMock = $this->createMock('Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Collector\\SystemInfoCollector');
+            $this->collectorMock = $this->createMock(SystemInfoCollector::class);
         }
 
         return $this->collectorMock;
diff --git a/tests/lib/EventListener/SystemInfoTabGroupListenerTest.php b/tests/lib/EventListener/SystemInfoTabGroupListenerTest.php
index f7d7d59..eaa8b2b 100644
--- a/tests/lib/EventListener/SystemInfoTabGroupListenerTest.php
+++ b/tests/lib/EventListener/SystemInfoTabGroupListenerTest.php
@@ -20,15 +20,9 @@
 
 class SystemInfoTabGroupListenerTest extends TestCase
 {
-    /** @var \Symfony\Component\HttpFoundation\Request */
-    private $request;
-
     /** @var \Ibexa\AdminUi\Tab\Event\TabGroupEvent */
     private $event;
 
-    /** @var \Symfony\Component\HttpKernel\HttpKernelInterface|\PHPUnit\Framework\MockObject\MockObject */
-    private $httpKernel;
-
     /** @var \PHPUnit\Framework\MockObject\MockObject|\Ibexa\AdminUi\Tab\TabRegistry */
     private $tabRegistry;
 
@@ -42,16 +36,10 @@ protected function setUp(): void
         $this->tabRegistry = $this->createMock(TabRegistry::class);
         $this->tabFactory = $this->createMock(TabFactory::class);
 
-        $this->request = $this
-            ->getMockBuilder(Request::class)
-            ->setMethods(['getSession', 'hasSession'])
-            ->getMock();
-
-        $this->httpKernel = $this->createMock(HttpKernelInterface::class);
         $this->event = new TabGroupEvent();
     }
 
-    public function testOnTabGroupPreRenderWithNoSystemInfoTabGroup()
+    public function testOnTabGroupPreRenderWithNoSystemInfoTabGroup(): void
     {
         $systemInfoCollectorRegistry = $this->createMock(SystemInfoCollectorRegistry::class);
         $systemInfoCollectorRegistry->expects(self::never())
@@ -70,7 +58,7 @@ public function testOnTabGroupPreRenderWithNoSystemInfoTabGroup()
      *
      * @param string[] $identifiers
      */
-    public function testOnTabGroupPreRender($identifiers)
+    public function testOnTabGroupPreRender(array $identifiers): void
     {
         foreach ($identifiers as $i => $identifier) {
             $tab = $this->createMock(SystemInfoTab::class);
@@ -95,7 +83,7 @@ public function testOnTabGroupPreRender($identifiers)
         $systemInfoTabGroupListener->onTabGroupPreRender($this->event);
     }
 
-    public function testSubscribedEvents()
+    public function testSubscribedEvents(): void
     {
         $systemInfoCollectorRegistry = $this->createMock(SystemInfoCollectorRegistry::class);
         $systemInfoTabGroupListener = new SystemInfoTabGroupListener($this->tabRegistry, $this->tabFactory, $systemInfoCollectorRegistry);
@@ -103,6 +91,9 @@ public function testSubscribedEvents()
         $this->assertSame([TabEvents::TAB_GROUP_PRE_RENDER => ['onTabGroupPreRender', 10]], $systemInfoTabGroupListener::getSubscribedEvents());
     }
 
+    /**
+     * @return array<string, array<array<string>>>
+     */
     public function dataProvider(): array
     {
         return [
diff --git a/tests/lib/VersionStability/VersionStabilityCheckerTest.php b/tests/lib/VersionStability/VersionStabilityCheckerTest.php
index fa6d7b5..d0f4fe0 100644
--- a/tests/lib/VersionStability/VersionStabilityCheckerTest.php
+++ b/tests/lib/VersionStability/VersionStabilityCheckerTest.php
@@ -32,6 +32,9 @@ public function testIsStableVersion(string $stableVersion): void
         );
     }
 
+    /**
+     * @return iterable<array{string}>
+     */
     public function provideStableVersions(): iterable
     {
         yield ['1.0.0.0'];
@@ -51,6 +54,9 @@ public function testIsNotStableVersion(string $notStableVersion): void
         );
     }
 
+    /**
+     * @return iterable<array{string}>
+     */
     public function provideNotStableVersions(): iterable
     {
         yield ['1.0.20'];
@@ -79,6 +85,9 @@ public function testGetStability(
         );
     }
 
+    /**
+     * @return iterable<array{string, string}>
+     */
     public function provideVersions(): iterable
     {
         yield ['0.1.10.50', Stability::STABILITIES[0]];

From dd2255080570023560362f16af9116ab7e1707df Mon Sep 17 00:00:00 2001
From: Dawid Parafinski <dawid.parafinski@ibexa.co>
Date: Mon, 23 Dec 2024 12:31:56 +0100
Subject: [PATCH 3/4] fixed cs

---
 .../Controller/SystemInfoController.php       |  1 +
 .../Collector/IbexaSystemInfoCollector.php    |  2 +-
 .../JsonComposerLockSystemInfoCollector.php   |  1 -
 .../SystemInfo/EzcSystemInfoWrapper.php       | 24 +++++++++----------
 .../OutputFormat/JsonOutputFormat.php         |  1 +
 src/bundle/View/SystemInfoView.php            |  1 +
 src/bundle/View/SystemInfoViewBuilder.php     |  1 -
 .../Dashboard/EzInfoTwigComponent.php         |  2 +-
 .../EzcPhpSystemInfoCollectorTest.php         |  7 ++++--
 .../RepositorySystemInfoCollectorTest.php     |  2 +-
 .../Registry/IdentifierBasedTest.php          | 10 ++++----
 .../bundle/View/SystemInfoViewBuilderTest.php |  7 +++---
 .../SystemInfoTabGroupListenerTest.php        |  2 --
 13 files changed, 32 insertions(+), 29 deletions(-)

diff --git a/src/bundle/Controller/SystemInfoController.php b/src/bundle/Controller/SystemInfoController.php
index 36c3026..b5fcffd 100644
--- a/src/bundle/Controller/SystemInfoController.php
+++ b/src/bundle/Controller/SystemInfoController.php
@@ -55,6 +55,7 @@ public function phpinfoAction(): Response
     {
         ob_start();
         phpinfo();
+
         return new Response(ob_get_clean() ?: '');
     }
 }
diff --git a/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php b/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php
index 02e52ae..87d185c 100644
--- a/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php
+++ b/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php
@@ -133,7 +133,7 @@ class IbexaSystemInfoCollector implements SystemInfoCollector
     ];
 
     /**
-     * @var ComposerSystemInfo|null
+     * @var \Ibexa\Bundle\SystemInfo\SystemInfo\Value\ComposerSystemInfo|null
      */
     private $composerInfo;
 
diff --git a/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php b/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php
index 453f4df..c20ceab 100644
--- a/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php
+++ b/src/bundle/SystemInfo/Collector/JsonComposerLockSystemInfoCollector.php
@@ -10,7 +10,6 @@
 use Ibexa\Bundle\SystemInfo\SystemInfo\Exception;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Value\ComposerPackage;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Value\ComposerSystemInfo;
-use Ibexa\Bundle\SystemInfo\SystemInfo\Value\SystemInfo;
 use Ibexa\SystemInfo\Value\Stability;
 use Ibexa\SystemInfo\VersionStability\VersionStabilityChecker;
 
diff --git a/src/bundle/SystemInfo/EzcSystemInfoWrapper.php b/src/bundle/SystemInfo/EzcSystemInfoWrapper.php
index 9dd5348..66a86d1 100644
--- a/src/bundle/SystemInfo/EzcSystemInfoWrapper.php
+++ b/src/bundle/SystemInfo/EzcSystemInfoWrapper.php
@@ -16,30 +16,30 @@
  */
 class EzcSystemInfoWrapper
 {
-    public string $osType;
+    public ?string $osType;
 
-    public string $osName;
+    public ?string $osName;
 
-    public string $fileSystemType;
+    public ?string $fileSystemType;
 
-    public int $cpuCount;
+    public ?int $cpuCount;
 
-    public string $cpuType;
+    public ?string $cpuType;
 
-    public float $cpuSpeed;
+    public ?float $cpuSpeed;
 
     /** @var int */
-    public int $memorySize;
+    public ?int $memorySize;
 
-    public string $lineSeparator;
+    public ?string $lineSeparator;
 
-    public string $backupFileName;
+    public ?string $backupFileName;
 
-    public string $phpVersion;
+    public ?string $phpVersion;
 
-    public ezcSystemInfoAccelerator $phpAccelerator;
+    public ?ezcSystemInfoAccelerator $phpAccelerator;
 
-    public bool $isShellExecution;
+    public ?bool $isShellExecution;
 
     public function __construct()
     {
diff --git a/src/bundle/SystemInfo/OutputFormat/JsonOutputFormat.php b/src/bundle/SystemInfo/OutputFormat/JsonOutputFormat.php
index 4c4f75a..b19d36c 100644
--- a/src/bundle/SystemInfo/OutputFormat/JsonOutputFormat.php
+++ b/src/bundle/SystemInfo/OutputFormat/JsonOutputFormat.php
@@ -19,6 +19,7 @@ public function format(array $collectedInfo)
         if ($json === false) {
             return '';
         }
+
         return $json;
     }
 }
diff --git a/src/bundle/View/SystemInfoView.php b/src/bundle/View/SystemInfoView.php
index d5c1095..449e9b8 100644
--- a/src/bundle/View/SystemInfoView.php
+++ b/src/bundle/View/SystemInfoView.php
@@ -20,6 +20,7 @@ public function setInfo(SystemInfo $info): self
 
         return $this;
     }
+
     public function getInfo(): SystemInfo
     {
         return $this->info;
diff --git a/src/bundle/View/SystemInfoViewBuilder.php b/src/bundle/View/SystemInfoViewBuilder.php
index 4f680f6..2c64925 100644
--- a/src/bundle/View/SystemInfoViewBuilder.php
+++ b/src/bundle/View/SystemInfoViewBuilder.php
@@ -10,7 +10,6 @@
 use Ibexa\Bundle\SystemInfo\SystemInfo\Exception\SystemInfoException;
 use Ibexa\Bundle\SystemInfo\SystemInfo\SystemInfoCollectorRegistry;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Value\InvalidSystemInfo;
-use Ibexa\Core\MVC\Symfony\View\BaseView;
 use Ibexa\Core\MVC\Symfony\View\Builder\ViewBuilder;
 use Ibexa\Core\MVC\Symfony\View\Configurator;
 use Ibexa\Core\MVC\Symfony\View\View;
diff --git a/src/lib/Component/Dashboard/EzInfoTwigComponent.php b/src/lib/Component/Dashboard/EzInfoTwigComponent.php
index ddb5ce9..6be8eee 100644
--- a/src/lib/Component/Dashboard/EzInfoTwigComponent.php
+++ b/src/lib/Component/Dashboard/EzInfoTwigComponent.php
@@ -23,7 +23,7 @@ class EzInfoTwigComponent implements Renderable
 
     private IbexaSystemInfo $ibexaSystemInfo;
 
-    /** @var array<string, string>  */
+    /** @var array<string, string> */
     private array $urlList;
 
     /**
diff --git a/tests/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollectorTest.php b/tests/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollectorTest.php
index b0c44b5..cbf7d87 100644
--- a/tests/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollectorTest.php
+++ b/tests/bundle/SystemInfo/Collector/EzcPhpSystemInfoCollectorTest.php
@@ -6,7 +6,9 @@
  */
 namespace Ibexa\Tests\Bundle\SystemInfo\SystemInfo\Collector;
 
+use ezcSystemInfoAccelerator;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Collector\EzcPhpSystemInfoCollector;
+use Ibexa\Bundle\SystemInfo\SystemInfo\EzcSystemInfoWrapper;
 use Ibexa\Bundle\SystemInfo\SystemInfo\Value\PhpSystemInfo;
 use PHPUnit\Framework\TestCase;
 
@@ -25,13 +27,13 @@ class EzcPhpSystemInfoCollectorTest extends TestCase
     protected function setUp(): void
     {
         $this->ezcSystemInfoMock = $this
-            ->getMockBuilder('Ibexa\\Bundle\\SystemInfo\\SystemInfo\\EzcSystemInfoWrapper')
+            ->getMockBuilder(EzcSystemInfoWrapper::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->ezcSystemInfoMock->phpVersion = PHP_VERSION;
 
         $this->ezcSystemInfoMock->phpAccelerator = $this
-            ->getMockBuilder('ezcSystemInfoAccelerator')
+            ->getMockBuilder(ezcSystemInfoAccelerator::class)
             ->setConstructorArgs(
                 [
                     'Zend OPcache',
@@ -54,6 +56,7 @@ public function testCollect(): void
         $value = $this->ezcPhpCollector->collect();
 
         self::assertInstanceOf(PhpSystemInfo::class, $value);
+        self::assertInstanceOf(ezcSystemInfoAccelerator::class, $this->ezcSystemInfoMock->phpAccelerator);
 
         self::assertEquals(
             new PhpSystemInfo([
diff --git a/tests/bundle/SystemInfo/Collector/RepositorySystemInfoCollectorTest.php b/tests/bundle/SystemInfo/Collector/RepositorySystemInfoCollectorTest.php
index f8978e8..395429b 100644
--- a/tests/bundle/SystemInfo/Collector/RepositorySystemInfoCollectorTest.php
+++ b/tests/bundle/SystemInfo/Collector/RepositorySystemInfoCollectorTest.php
@@ -23,7 +23,7 @@ class RepositorySystemInfoCollectorTest extends TestCase
     private $dbalConnectionMock;
 
     /**
-     * @var \Doctrine\DBAL\Platforms\AbstractPlatform & \PHPUnit\Framework\MockObject\MockObject
+     * @var \Doctrine\DBAL\Platforms\AbstractPlatform&\PHPUnit\Framework\MockObject\MockObject
      */
     private $dbalPlatformMock;
 
diff --git a/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php b/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
index 7a853bd..0d26ec5 100644
--- a/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
+++ b/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
@@ -16,7 +16,7 @@ class IdentifierBasedTest extends TestCase
     private IdentifierBased $registry;
 
     /**
-     * @var \PHPUnit\Framework\MockObject\MockObject[]|SystemInfoCollector[]
+     * @var \PHPUnit\Framework\MockObject\MockObject[]|\Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector[]
      */
     private array $testItems;
 
@@ -33,7 +33,7 @@ protected function setUp(): void
     /**
      * Test adding items to the registry, and getting items from it.
      *
-     * @covers IdentifierBased::getItem
+     * @covers \IdentifierBased::getItem
      */
     public function testAddAndGetItems(): void
     {
@@ -46,7 +46,7 @@ public function testAddAndGetItems(): void
     /**
      * Test exception when registry item is not found.
      *
-     * @covers IdentifierBased::getItem
+     * @covers \IdentifierBased::getItem
      */
     public function testGetItemNotFound(): void
     {
@@ -57,7 +57,7 @@ public function testGetItemNotFound(): void
     /**
      * Test replacing an item in the registry.
      *
-     * @covers IdentifierBased::getItem
+     * @covers \IdentifierBased::getItem
      */
     public function testReplaceItem(): void
     {
@@ -76,7 +76,7 @@ public function testReplaceItem(): void
     /**
      * Test getting all registered identifiers.
      *
-     * @covers IdentifierBased::getIdentifiers
+     * @covers \IdentifierBased::getIdentifiers
      * @depends testAddAndGetItems
      */
     public function testGetIdentifiers(): void
diff --git a/tests/bundle/View/SystemInfoViewBuilderTest.php b/tests/bundle/View/SystemInfoViewBuilderTest.php
index 9ea05ca..a859a45 100644
--- a/tests/bundle/View/SystemInfoViewBuilderTest.php
+++ b/tests/bundle/View/SystemInfoViewBuilderTest.php
@@ -57,7 +57,7 @@ public function testBuildView(): void
     }
 
     /**
-     * @return \PHPUnit\Framework\MockObject\MockObject & \Ibexa\Core\MVC\Symfony\View\Configurator
+     * @return \PHPUnit\Framework\MockObject\MockObject&\Ibexa\Core\MVC\Symfony\View\Configurator
      */
     protected function getConfiguratorMock(): Configurator
     {
@@ -69,12 +69,13 @@ protected function getConfiguratorMock(): Configurator
     }
 
     /**
-     * @return \PHPUnit\Framework\MockObject\MockObject & \Ibexa\Bundle\SystemInfo\SystemInfo\SystemInfoCollectorRegistry
+     * @return \PHPUnit\Framework\MockObject\MockObject&\Ibexa\Bundle\SystemInfo\SystemInfo\SystemInfoCollectorRegistry
      */
     protected function getRegistryMock(): SystemInfoCollectorRegistry
     {
         if (!isset($this->registryMock)) {
-            $this->registryMock = $this->createMock(SystemInfoCollectorRegistry::class
+            $this->registryMock = $this->createMock(
+                SystemInfoCollectorRegistry::class
             );
         }
 
diff --git a/tests/lib/EventListener/SystemInfoTabGroupListenerTest.php b/tests/lib/EventListener/SystemInfoTabGroupListenerTest.php
index eaa8b2b..9d867ac 100644
--- a/tests/lib/EventListener/SystemInfoTabGroupListenerTest.php
+++ b/tests/lib/EventListener/SystemInfoTabGroupListenerTest.php
@@ -15,8 +15,6 @@
 use Ibexa\SystemInfo\Tab\SystemInfo\SystemInfoTab;
 use Ibexa\SystemInfo\Tab\SystemInfo\TabFactory;
 use PHPUnit\Framework\TestCase;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
 
 class SystemInfoTabGroupListenerTest extends TestCase
 {

From 8e9c2c9aef28e5c73746916ae477c1b33e51187a Mon Sep 17 00:00:00 2001
From: Dawid Parafinski <dawid.parafinski@ibexa.co>
Date: Mon, 23 Dec 2024 13:47:36 +0100
Subject: [PATCH 4/4] fixed even more issues after CR

---
 phpstan-baseline.neon                         | 18 -------------
 .../IbexaSystemInfoExtension.php              |  5 +---
 .../Collector/IbexaSystemInfoCollector.php    |  9 +------
 .../Registry/IdentifierBasedTest.php          |  8 +++---
 .../bundle/View/SystemInfoViewBuilderTest.php | 27 ++++++++++---------
 5 files changed, 21 insertions(+), 46 deletions(-)

diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index ec67bc8..fb338b9 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -23,21 +23,3 @@ parameters:
 			identifier: argument.type
 			count: 3
 			path: tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
-
-		-
-			message: '#^Method Ibexa\\Tests\\Bundle\\SystemInfo\\View\\SystemInfoViewBuilderTest\:\:getCollectorMock\(\) should return Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Collector\\SystemInfoCollector&PHPUnit\\Framework\\MockObject\\MockObject but returns Ibexa\\Bundle\\SystemInfo\\SystemInfo\\Collector\\SystemInfoCollector\.$#'
-			identifier: return.type
-			count: 1
-			path: tests/bundle/View/SystemInfoViewBuilderTest.php
-
-		-
-			message: '#^Method Ibexa\\Tests\\Bundle\\SystemInfo\\View\\SystemInfoViewBuilderTest\:\:getConfiguratorMock\(\) should return Ibexa\\Core\\MVC\\Symfony\\View\\Configurator&PHPUnit\\Framework\\MockObject\\MockObject but returns Ibexa\\Core\\MVC\\Symfony\\View\\Configurator\.$#'
-			identifier: return.type
-			count: 1
-			path: tests/bundle/View/SystemInfoViewBuilderTest.php
-
-		-
-			message: '#^Method Ibexa\\Tests\\Bundle\\SystemInfo\\View\\SystemInfoViewBuilderTest\:\:getRegistryMock\(\) should return Ibexa\\Bundle\\SystemInfo\\SystemInfo\\SystemInfoCollectorRegistry&PHPUnit\\Framework\\MockObject\\MockObject but returns Ibexa\\Bundle\\SystemInfo\\SystemInfo\\SystemInfoCollectorRegistry\.$#'
-			identifier: return.type
-			count: 1
-			path: tests/bundle/View/SystemInfoViewBuilderTest.php
diff --git a/src/bundle/DependencyInjection/IbexaSystemInfoExtension.php b/src/bundle/DependencyInjection/IbexaSystemInfoExtension.php
index 7f2be65..fea6714 100644
--- a/src/bundle/DependencyInjection/IbexaSystemInfoExtension.php
+++ b/src/bundle/DependencyInjection/IbexaSystemInfoExtension.php
@@ -29,10 +29,7 @@ public function getAlias()
         return self::EXTENSION_NAME;
     }
 
-    /**
-     * @return \Ibexa\Bundle\SystemInfo\DependencyInjection\Configuration
-     */
-    public function getConfiguration(array $config, ContainerBuilder $container)
+    public function getConfiguration(array $config, ContainerBuilder $container): Configuration
     {
         return new Configuration();
     }
diff --git a/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php b/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php
index 87d185c..458e9e0 100644
--- a/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php
+++ b/src/bundle/SystemInfo/Collector/IbexaSystemInfoCollector.php
@@ -145,10 +145,6 @@ class IbexaSystemInfoCollector implements SystemInfoCollector
     /** @var string */
     private $kernelProjectDir;
 
-    /**
-     * @param \Ibexa\Bundle\SystemInfo\SystemInfo\Collector\JsonComposerLockSystemInfoCollector|SystemInfoCollector $composerCollector
-     * @param bool $debug
-     */
     public function __construct(
         SystemInfoCollector $composerCollector,
         string $kernelProjectDir,
@@ -251,11 +247,8 @@ private static function getStability(ComposerSystemInfo $composerInfo): string
             $stabilityFlags[$composerInfo->minimumStability] :
             $stabilityFlags['stable'];
 
-        if ($composerInfo->packages === null) {
-            return Stability::STABILITIES[$stabilityFlag];
-        }
         // Check if any of the watched packages has lower stability than root
-        foreach ($composerInfo->packages as $name => $package) {
+        foreach ($composerInfo->packages ?? [] as $name => $package) {
             if (!preg_match(self::PACKAGE_WATCH_REGEX, $name)) {
                 continue;
             }
diff --git a/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php b/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
index 0d26ec5..62daae2 100644
--- a/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
+++ b/tests/bundle/SystemInfo/Registry/IdentifierBasedTest.php
@@ -33,7 +33,7 @@ protected function setUp(): void
     /**
      * Test adding items to the registry, and getting items from it.
      *
-     * @covers \IdentifierBased::getItem
+     * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Registry\IdentifierBased::getItem
      */
     public function testAddAndGetItems(): void
     {
@@ -46,7 +46,7 @@ public function testAddAndGetItems(): void
     /**
      * Test exception when registry item is not found.
      *
-     * @covers \IdentifierBased::getItem
+     * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Registry\IdentifierBased::getItem
      */
     public function testGetItemNotFound(): void
     {
@@ -57,7 +57,7 @@ public function testGetItemNotFound(): void
     /**
      * Test replacing an item in the registry.
      *
-     * @covers \IdentifierBased::getItem
+     * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Registry\IdentifierBased::getItem
      */
     public function testReplaceItem(): void
     {
@@ -76,7 +76,7 @@ public function testReplaceItem(): void
     /**
      * Test getting all registered identifiers.
      *
-     * @covers \IdentifierBased::getIdentifiers
+     * @covers \Ibexa\Bundle\SystemInfo\SystemInfo\Registry\IdentifierBased::getItem
      * @depends testAddAndGetItems
      */
     public function testGetIdentifiers(): void
diff --git a/tests/bundle/View/SystemInfoViewBuilderTest.php b/tests/bundle/View/SystemInfoViewBuilderTest.php
index a859a45..ced8511 100644
--- a/tests/bundle/View/SystemInfoViewBuilderTest.php
+++ b/tests/bundle/View/SystemInfoViewBuilderTest.php
@@ -15,10 +15,19 @@
 
 class SystemInfoViewBuilderTest extends TestCase
 {
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject&\Ibexa\Core\MVC\Symfony\View\Configurator
+     */
     private Configurator $configuratorMock;
 
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject&\Ibexa\Bundle\SystemInfo\SystemInfo\SystemInfoCollectorRegistry
+     */
     private SystemInfoCollectorRegistry $registryMock;
 
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject&\Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector
+     */
     private SystemInfoCollector $collectorMock;
 
     public function testMatches(): void
@@ -61,9 +70,7 @@ public function testBuildView(): void
      */
     protected function getConfiguratorMock(): Configurator
     {
-        if (!isset($this->configuratorMock)) {
-            $this->configuratorMock = $this->createMock(Configurator::class);
-        }
+        $this->configuratorMock ??= $this->createMock(Configurator::class);
 
         return $this->configuratorMock;
     }
@@ -73,23 +80,19 @@ protected function getConfiguratorMock(): Configurator
      */
     protected function getRegistryMock(): SystemInfoCollectorRegistry
     {
-        if (!isset($this->registryMock)) {
-            $this->registryMock = $this->createMock(
-                SystemInfoCollectorRegistry::class
-            );
-        }
+        $this->registryMock ??= $this->createMock(
+            SystemInfoCollectorRegistry::class
+        );
 
         return $this->registryMock;
     }
 
     /**
-     * @return \PHPUnit\Framework\MockObject\MockObject|\Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector
+     * @return \PHPUnit\Framework\MockObject\MockObject&\Ibexa\Bundle\SystemInfo\SystemInfo\Collector\SystemInfoCollector
      */
     protected function getCollectorMock(): SystemInfoCollector
     {
-        if (!isset($this->collectorMock)) {
-            $this->collectorMock = $this->createMock(SystemInfoCollector::class);
-        }
+        $this->collectorMock ??= $this->createMock(SystemInfoCollector::class);
 
         return $this->collectorMock;
     }