Skip to content

Commit 9e810ef

Browse files
authored
IBX-9727: Added missing strict types and adapted the codebase to PHP 8.3 (#38)
1 parent a8921e2 commit 9e810ef

20 files changed

+188
-98
lines changed

.github/workflows/ci.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,6 @@ jobs:
8989

9090
- name: Run unit test suite
9191
run: composer test
92+
93+
- name: Run PHPStan analysis
94+
run: composer run-script phpstan

composer.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
"ibexa/doctrine-schema": "~5.0.x-dev",
3535
"ibexa/rector": "~5.0.x-dev",
3636
"mikey179/vfsstream": "^1.6",
37+
"phpstan/phpstan": "^2.0",
38+
"phpstan/phpstan-phpunit": "^2.0",
39+
"phpstan/phpstan-symfony": "^2.0",
3740
"phpunit/phpunit": "^9.6"
3841
},
3942
"autoload": {
@@ -52,7 +55,8 @@
5255
"scripts": {
5356
"fix-cs": "php-cs-fixer fix --config=.php-cs-fixer.php -v --show-progress=dots",
5457
"check-cs": "@fix-cs --dry-run",
55-
"test": "phpunit"
58+
"test": "phpunit",
59+
"phpstan": "phpstan analyse"
5660
},
5761
"extra": {
5862
"branch-alias": {

phpstan-baseline.neon

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
parameters:
2+
ignoreErrors:
3+
-
4+
message: '#^Class Ibexa\\Bundle\\DesignEngine\\DataCollector\\TwigDataCollector extends @final class Symfony\\Bridge\\Twig\\DataCollector\\TwigDataCollector\.$#'
5+
identifier: class.extendsFinalByPhpDoc
6+
count: 1
7+
path: src/bundle/DataCollector/TwigDataCollector.php
8+
9+
-
10+
message: '#^Parameter \#1 \$provisioner of method Ibexa\\Bundle\\DesignEngine\\DependencyInjection\\Compiler\\AssetPathResolutionPass\:\:preResolveAssetsPaths\(\) expects Ibexa\\DesignEngine\\Asset\\AssetPathProvisionerInterface, object given\.$#'
11+
identifier: argument.type
12+
count: 1
13+
path: src/bundle/DependencyInjection/Compiler/AssetPathResolutionPass.php
14+
15+
-
16+
message: '#^Parameter \#2 \$designPathMap of method Ibexa\\Bundle\\DesignEngine\\DependencyInjection\\Compiler\\AssetPathResolutionPass\:\:preResolveAssetsPaths\(\) expects array\<string, list\<string\>\>, array\|bool\|float\|int\|string\|null given\.$#'
17+
identifier: argument.type
18+
count: 1
19+
path: src/bundle/DependencyInjection/Compiler/AssetPathResolutionPass.php
20+
21+
-
22+
message: '#^Parameter \#3 \$length of function substr expects int\|null, int\|false given\.$#'
23+
identifier: argument.type
24+
count: 1
25+
path: src/bundle/DependencyInjection/Compiler/AssetThemePass.php
26+
27+
-
28+
message: '#^PHPDoc tag @var with type SplFileInfo is not subtype of native type Symfony\\Component\\Finder\\SplFileInfo\.$#'
29+
identifier: varTag.nativeType
30+
count: 1
31+
path: src/lib/Asset/ProvisionedPathResolver.php

phpstan.neon

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
includes:
2+
- phpstan-baseline.neon
3+
- vendor/phpstan/phpstan-phpunit/extension.neon
4+
- vendor/phpstan/phpstan-symfony/extension.neon
5+
6+
parameters:
7+
level: 8
8+
paths:
9+
- src
10+
- tests
11+
treatPhpDocTypesAsCertain: false

src/bundle/DataCollector/TwigDataCollector.php

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,30 @@
1414

1515
class TwigDataCollector extends BaseCollector
1616
{
17-
private TemplatePathRegistryInterface $templatePathRegistry;
18-
19-
public function __construct(Profile $profile, Environment $environment, TemplatePathRegistryInterface $templatePathRegistry)
20-
{
17+
public function __construct(
18+
Profile $profile,
19+
Environment $environment,
20+
private TemplatePathRegistryInterface $templatePathRegistry
21+
) {
2122
parent::__construct($profile, $environment);
22-
$this->templatePathRegistry = $templatePathRegistry;
2323
}
2424

25-
private function getTemplatePathRegistry()
25+
private function getTemplatePathRegistry(): TemplatePathRegistryInterface
2626
{
27-
if (!isset($this->templatePathRegistry)) {
28-
$this->templatePathRegistry = unserialize($this->data['template_path_registry']);
29-
}
30-
3127
return $this->templatePathRegistry;
3228
}
3329

30+
#[\Override]
3431
public function lateCollect(): void
3532
{
3633
parent::lateCollect();
3734
$this->data['template_path_registry'] = serialize($this->templatePathRegistry);
3835
}
3936

37+
/**
38+
* @return array<string, int>
39+
*/
40+
#[\Override]
4041
public function getTemplates(): array
4142
{
4243
$registry = $this->getTemplatePathRegistry();

src/bundle/DependencyInjection/Compiler/AssetPathResolutionPass.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ public function process(ContainerBuilder $container): void
4242
$container->setAlias('ibexadesign.asset_path_resolver', new Alias(ProvisionedPathResolver::class));
4343
}
4444

45+
/**
46+
* @param array<string, list<string>> $designPathMap
47+
*
48+
* @return array<string, array<string, string>>
49+
*/
4550
private function preResolveAssetsPaths(AssetPathProvisionerInterface $provisioner, array $designPathMap): array
4651
{
4752
$resolvedPathsByDesign = [];

src/bundle/DependencyInjection/Compiler/AssetThemePass.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,20 @@ public function process(ContainerBuilder $container): void
2121
return;
2222
}
2323

24+
$overridePaths = $container->getParameter('ibexa.design.assets.override_paths');
2425
$themesPathMap = [
2526
'_override' => array_merge(
2627
['assets'],
27-
$container->getParameter('ibexa.design.assets.override_paths')
28+
(array)$overridePaths,
2829
),
2930
];
3031
$finder = new Finder();
3132
// Look for assets themes in bundles.
32-
foreach ($container->getParameter('kernel.bundles') as $bundleName => $bundleClass) {
33+
foreach ((array)$container->getParameter('kernel.bundles') as $bundleName => $bundleClass) {
3334
$bundleReflection = new \ReflectionClass($bundleClass);
34-
$bundleViewsDir = \dirname($bundleReflection->getFileName()) . '/Resources/public';
35+
$fileName = $bundleReflection->getFileName();
36+
assert(is_string($fileName));
37+
$bundleViewsDir = \dirname($fileName) . '/Resources/public';
3538
$themeDir = $bundleViewsDir . '/themes';
3639
if (!is_dir($themeDir)) {
3740
continue;
@@ -46,7 +49,9 @@ public function process(ContainerBuilder $container): void
4649
}
4750

4851
// Look for assets themes at application level (web/assets/themes).
49-
$appLevelThemeDir = $container->getParameter('webroot_dir') . '/assets/themes';
52+
$webrootDir = $container->getParameter('webroot_dir');
53+
assert(is_string($webrootDir));
54+
$appLevelThemeDir = $webrootDir . '/assets/themes';
5055
if (is_dir($appLevelThemeDir)) {
5156
foreach ((new Finder())->directories()->in($appLevelThemeDir)->depth('== 0') as $directoryInfo) {
5257
$theme = $directoryInfo->getBasename();
@@ -62,7 +67,7 @@ public function process(ContainerBuilder $container): void
6267
}
6368

6469
$pathsByDesign = [];
65-
foreach ($container->getParameter('ibexa.design.list') as $designName => $themeFallback) {
70+
foreach ((array)$container->getParameter('ibexa.design.list') as $designName => $themeFallback) {
6671
// Always add _override theme first.
6772
array_unshift($themeFallback, '_override');
6873
foreach ($themeFallback as $theme) {
@@ -77,7 +82,7 @@ public function process(ContainerBuilder $container): void
7782
}
7883
}
7984

80-
$themesList = $container->getParameter('ibexa.design.themes.list');
85+
$themesList = (array)$container->getParameter('ibexa.design.themes.list');
8186
$container->setParameter(
8287
'ibexa.design.themes.list',
8388
array_unique(

src/bundle/DependencyInjection/Compiler/TwigThemePass.php

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@ public function process(ContainerBuilder $container): void
3333
}
3434

3535
$themesPathMap = [
36-
'_override' => $container->getParameter('ibexa.design.templates.override_paths'),
36+
'_override' => (array)$container->getParameter('ibexa.design.templates.override_paths'),
3737
];
3838
$finder = new Finder();
3939
// Look for themes in bundles.
40-
foreach ($container->getParameter('kernel.bundles') as $bundleName => $bundleClass) {
40+
foreach ((array)$container->getParameter('kernel.bundles') as $bundleName => $bundleClass) {
4141
$bundleReflection = new ReflectionClass($bundleClass);
42-
$bundleViewsDir = \dirname($bundleReflection->getFileName()) . '/Resources/views';
42+
$filename = $bundleReflection->getFileName();
43+
assert(is_string($filename));
44+
$bundleViewsDir = \dirname($filename) . '/Resources/views';
4345
$themeDir = $bundleViewsDir . '/themes';
4446
if (!is_dir($themeDir)) {
4547
continue;
@@ -53,9 +55,9 @@ public function process(ContainerBuilder $container): void
5355

5456
$twigLoaderDef = $container->findDefinition(TwigThemeLoader::class);
5557
// Now look for themes at application level
56-
$appLevelThemesDir = $container->getParameterBag()->resolveValue(
57-
$container->getParameter('twig.default_path') . '/themes'
58-
);
58+
$twigDefaultPath = $container->getParameter('twig.default_path');
59+
assert(is_string($twigDefaultPath));
60+
$appLevelThemesDir = $container->getParameterBag()->resolveValue($twigDefaultPath . '/themes');
5961

6062
if (is_dir($appLevelThemesDir)) {
6163
foreach ((new Finder())->directories()->in($appLevelThemesDir)->depth('== 0') as $directoryInfo) {
@@ -69,14 +71,17 @@ public function process(ContainerBuilder $container): void
6971

7072
// Now merge with already configured template theme paths
7173
// Template theme paths defined via config will always have less priority than convention based paths
72-
$themesPathMap = array_merge_recursive($themesPathMap, $container->getParameter('ibexa.design.templates.path_map'));
74+
$themesPathMap = array_merge_recursive(
75+
$themesPathMap,
76+
(array)$container->getParameter('ibexa.design.templates.path_map'),
77+
);
7378

7479
// De-duplicate the map
7580
foreach ($themesPathMap as $theme => &$paths) {
7681
$paths = array_unique($paths);
7782
}
7883

79-
foreach ($container->getParameter('ibexa.design.list') as $designName => $themeFallback) {
84+
foreach ((array)$container->getParameter('ibexa.design.list') as $designName => $themeFallback) {
8085
// Always add _override theme first.
8186
array_unshift($themeFallback, '_override');
8287
foreach ($themeFallback as $theme) {
@@ -91,7 +96,7 @@ public function process(ContainerBuilder $container): void
9196
}
9297
}
9398

94-
$themesList = $container->getParameter('ibexa.design.themes.list');
99+
$themesList = (array)$container->getParameter('ibexa.design.themes.list');
95100
$container->setParameter(
96101
'ibexa.design.themes.list',
97102
array_unique(

src/bundle/DependencyInjection/DesignConfigParser.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,28 @@
1313

1414
class DesignConfigParser implements ParserInterface
1515
{
16+
/**
17+
* @param array<string, mixed> $scopeSettings
18+
* @param string $currentScope
19+
*/
1620
public function mapConfig(array &$scopeSettings, $currentScope, ContextualizerInterface $contextualizer): void
1721
{
1822
if (isset($scopeSettings['design'])) {
1923
$contextualizer->setContextualParameter('design', $currentScope, $scopeSettings['design']);
2024
}
2125
}
2226

27+
/**
28+
* @param array<string, mixed> $config
29+
*/
2330
public function preMap(array $config, ContextualizerInterface $contextualizer): void
2431
{
2532
// Nothing to map
2633
}
2734

35+
/**
36+
* @param array<string, mixed> $config
37+
*/
2838
public function postMap(array $config, ContextualizerInterface $contextualizer): void
2939
{
3040
// Nothing to map

src/bundle/DependencyInjection/IbexaDesignEngineExtension.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
namespace Ibexa\Bundle\DesignEngine\DependencyInjection;
99

10-
use Ibexa\Bundle\Core\DependencyInjection\Configuration\SiteAccessAware\ConfigurationProcessor;
1110
use Symfony\Component\Config\Definition\ConfigurationInterface;
1211
use Symfony\Component\Config\FileLocator;
1312
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -18,11 +17,16 @@ class IbexaDesignEngineExtension extends Extension
1817
{
1918
public const string EXTENSION_NAME = 'ibexa_design_engine';
2019

20+
#[\Override]
2121
public function getAlias(): string
2222
{
2323
return self::EXTENSION_NAME;
2424
}
2525

26+
/**
27+
* @param array<string, mixed> $config
28+
*/
29+
#[\Override]
2630
public function getConfiguration(array $config, ContainerBuilder $container): ?ConfigurationInterface
2731
{
2832
return new Configuration();
@@ -40,12 +44,14 @@ public function load(array $configs, ContainerBuilder $container): void
4044
$configuration = $this->getConfiguration($configs, $container);
4145
assert(null !== $configuration);
4246
$config = $this->processConfiguration($configuration, $configs);
43-
$processor = new ConfigurationProcessor($container, 'ezdesign');
4447

45-
$this->configureDesigns($config, $processor, $container);
48+
$this->configureDesigns($config, $container);
4649
}
4750

48-
private function configureDesigns(array $config, ConfigurationProcessor $processor, ContainerBuilder $container): void
51+
/**
52+
* @param array<string, mixed> $config
53+
*/
54+
private function configureDesigns(array $config, ContainerBuilder $container): void
4955
{
5056
// Always add "standard" design to the list (defaults to application level & override paths only)
5157
$config['design_list'] += ['standard' => []];

0 commit comments

Comments
 (0)