Skip to content

Commit dd65314

Browse files
authored
Allow specific argument type checks for factories (#14)
1 parent 4b44060 commit dd65314

File tree

5 files changed

+70
-4
lines changed

5 files changed

+70
-4
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ This extension provides the following features:
1919

2020
### Rules
2121

22-
* Checks if the string argument passed to `config()` or `model()` function is a valid class string extending `CodeIgniter\Config\BaseConfig` or `CodeIgniter\Model`, respectively. This can be turned off by setting `codeigniter.checkArgumentTypeOfFactories: false` in your `phpstan.neon`.
22+
* Checks if the string argument passed to `config()` or `model()` function is a valid class string extending
23+
`CodeIgniter\Config\BaseConfig` or `CodeIgniter\Model`, respectively. This can be turned off by setting
24+
`codeigniter.checkArgumentTypeOfFactories: false` in your `phpstan.neon`. For fine-grained control, you can
25+
individually choose which factory function to disable using `codeigniter.checkArgumentTypeOfConfig` and
26+
`codeigniter.checkArgumentTypeOfModel`. **NOTE:** Setting `codeigniter.checkArgumentTypeOfFactories: false` will effectively
27+
bypass the two specific options.
2328
* Checks if the string argument passed to `service()` or `single_service()` function is a valid service name. This can be turned off by setting `codeigniter.checkArgumentTypeOfServices: false` in your `phpstan.neon`.
2429
* Disallows instantiating cache handlers using `new` and suggests to use the `CacheFactory` class instead.
2530
* Disallows instantiating `FrameworkException` classes using `new`.

extension.neon

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ parameters:
1212
additionalServices: []
1313
notStringFormattedFields: []
1414
checkArgumentTypeOfFactories: true
15+
checkArgumentTypeOfConfig: true
16+
checkArgumentTypeOfModel: true
1517
checkArgumentTypeOfServices: true
1618

1719
parametersSchema:
@@ -21,6 +23,8 @@ parametersSchema:
2123
additionalServices: listOf(string())
2224
notStringFormattedFields: arrayOf(string())
2325
checkArgumentTypeOfFactories: bool()
26+
checkArgumentTypeOfConfig: bool()
27+
checkArgumentTypeOfModel: bool()
2428
checkArgumentTypeOfServices: bool()
2529
])
2630

@@ -76,6 +80,9 @@ services:
7680
# conditional rules
7781
-
7882
class: CodeIgniter\PHPStan\Rules\Functions\FactoriesFunctionArgumentTypeRule
83+
arguments:
84+
checkArgumentTypeOfConfig: %codeigniter.checkArgumentTypeOfConfig%
85+
checkArgumentTypeOfModel: %codeigniter.checkArgumentTypeOfModel%
7986

8087
-
8188
class: CodeIgniter\PHPStan\Rules\Functions\ServicesFunctionArgumentTypeRule

src/Rules/Functions/FactoriesFunctionArgumentTypeRule.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,22 @@ final class FactoriesFunctionArgumentTypeRule implements Rule
3838
'model' => Model::class,
3939
];
4040

41+
/**
42+
* @var array<string, bool>
43+
*/
44+
private array $argumentTypeCheck = [];
45+
4146
public function __construct(
4247
private readonly ReflectionProvider $reflectionProvider,
43-
private readonly FactoriesReturnTypeHelper $factoriesReturnTypeHelper
44-
) {}
48+
private readonly FactoriesReturnTypeHelper $factoriesReturnTypeHelper,
49+
bool $checkArgumentTypeOfConfig,
50+
bool $checkArgumentTypeOfModel
51+
) {
52+
$this->argumentTypeCheck = [
53+
'config' => $checkArgumentTypeOfConfig,
54+
'model' => $checkArgumentTypeOfModel,
55+
];
56+
}
4557

4658
public function getNodeType(): string
4759
{
@@ -104,6 +116,10 @@ public function processNode(Node $node, Scope $scope): array
104116
}
105117

106118
if (! (new ObjectType($this->instanceofMap[$function]))->isSuperTypeOf($returnType)->yes()) {
119+
if (! $this->argumentTypeCheck[$function]) {
120+
return [];
121+
}
122+
107123
return [RuleErrorBuilder::message(sprintf(
108124
'Argument #1 $%s (%s) passed to function %s does not extend %s.',
109125
$firstParameter->getName(),
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter 4 framework.
7+
*
8+
* (c) 2023 CodeIgniter Foundation <[email protected]>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
class NotificationModel
15+
{
16+
public string $returnType = 'object';
17+
}
18+
19+
model(NotificationModel::class);

tests/Rules/Functions/FactoriesFunctionArgumentTypeRuleTest.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,24 @@ final class FactoriesFunctionArgumentTypeRuleTest extends RuleTestCase
3030
{
3131
use AdditionalConfigFilesTrait;
3232

33+
private bool $checkArgumentTypeOfConfig;
34+
private bool $checkArgumentTypeOfModel;
35+
36+
protected function setUp(): void
37+
{
38+
parent::setUp();
39+
40+
$this->checkArgumentTypeOfConfig = true;
41+
$this->checkArgumentTypeOfModel = true;
42+
}
43+
3344
protected function getRule(): Rule
3445
{
3546
return new FactoriesFunctionArgumentTypeRule(
3647
self::createReflectionProvider(),
37-
self::getContainer()->getByType(FactoriesReturnTypeHelper::class)
48+
self::getContainer()->getByType(FactoriesReturnTypeHelper::class),
49+
$this->checkArgumentTypeOfConfig,
50+
$this->checkArgumentTypeOfModel
3851
);
3952
}
4053

@@ -90,4 +103,10 @@ public function testRule(): void
90103
],
91104
]);
92105
}
106+
107+
public function testAllowNonModelClassesOnModelCall(): void
108+
{
109+
$this->checkArgumentTypeOfModel = false;
110+
$this->analyse([__DIR__ . '/../../Fixtures/Rules/Functions/bug-8.php'], []);
111+
}
93112
}

0 commit comments

Comments
 (0)