Skip to content

Commit 3e97210

Browse files
MakerTimTBiesenbeekmglaman
authored
Add DependencySerializationTraitPropertyRule (#731)
* Add rule for FormInterface that privates are no longer allowed (#730) * Comply with codestyle * support returning multiple errors * Make rule generic for all DependencySerializationTrait usages * make rule configurable * add tests * adjust error messages --------- Co-authored-by: TBiesenbeek <[email protected]> Co-authored-by: Matt Glaman <[email protected]>
1 parent 24fa3e9 commit 3e97210

File tree

5 files changed

+139
-0
lines changed

5 files changed

+139
-0
lines changed

extension.neon

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ parameters:
2121
checkDeprecatedHooksInApiFiles: false
2222
rules:
2323
testClassSuffixNameRule: false
24+
dependencySerializationTraitPropertyRule: false
2425
entityMapping:
2526
aggregator_feed:
2627
class: Drupal\aggregator\Entity\Feed
@@ -242,6 +243,7 @@ parametersSchema:
242243
])
243244
rules: structure([
244245
testClassSuffixNameRule: boolean()
246+
dependencySerializationTraitPropertyRule: boolean()
245247
])
246248
entityMapping: arrayOf(anyOf(
247249
structure([

rules.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ rules:
2323
conditionalTags:
2424
mglaman\PHPStanDrupal\Rules\Drupal\Tests\TestClassSuffixNameRule:
2525
phpstan.rules.rule: %drupal.rules.testClassSuffixNameRule%
26+
mglaman\PHPStanDrupal\Rules\Drupal\DependencySerializationTraitPropertyRule:
27+
phpstan.rules.rule: %drupal.rules.dependencySerializationTraitPropertyRule%
2628

2729
services:
2830
-
2931
class: mglaman\PHPStanDrupal\Rules\Drupal\Tests\TestClassSuffixNameRule
32+
-
33+
class: mglaman\PHPStanDrupal\Rules\Drupal\DependencySerializationTraitPropertyRule
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace mglaman\PHPStanDrupal\Rules\Drupal;
6+
7+
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
8+
use PhpParser\Node;
9+
use PHPStan\Analyser\Scope;
10+
use PHPStan\Node\ClassPropertyNode;
11+
use PHPStan\Rules\Rule;
12+
use PHPStan\Rules\RuleErrorBuilder;
13+
14+
/**
15+
* @implements Rule<ClassPropertyNode>
16+
*/
17+
final class DependencySerializationTraitPropertyRule implements Rule
18+
{
19+
20+
public function getNodeType(): string
21+
{
22+
return ClassPropertyNode::class;
23+
}
24+
25+
public function processNode(Node $node, Scope $scope): array
26+
{
27+
if (!$node->getClassReflection()->hasTraitUse(DependencySerializationTrait::class)) {
28+
return [];
29+
}
30+
31+
$errors = [];
32+
if ($node->isPrivate()) {
33+
$errors[] = RuleErrorBuilder::message(
34+
sprintf(
35+
'%s does not support private properties.',
36+
DependencySerializationTrait::class
37+
)
38+
)->tip('See https://www.drupal.org/node/3110266')->build();
39+
}
40+
if ($node->isReadOnly()) {
41+
$errors[] = RuleErrorBuilder::message(
42+
sprintf(
43+
'Read-only properties are incompatible with %s.',
44+
DependencySerializationTrait::class
45+
)
46+
)->tip('See https://www.drupal.org/node/3110266')->build();
47+
}
48+
return $errors;
49+
}
50+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace mglaman\PHPStanDrupal\Tests\Rules;
4+
5+
use mglaman\PHPStanDrupal\Rules\Drupal\DependencySerializationTraitPropertyRule;
6+
use mglaman\PHPStanDrupal\Tests\DrupalRuleTestCase;
7+
use PHPStan\Rules\Rule;
8+
9+
final class DependencySerializationTraitPropertyRuleTest extends DrupalRuleTestCase
10+
{
11+
12+
protected function getRule(): Rule
13+
{
14+
return new DependencySerializationTraitPropertyRule();
15+
}
16+
17+
public function testRule(): void
18+
{
19+
$this->analyse(
20+
[__DIR__.'/data/dependency-serialization-trait.php'],
21+
[
22+
[
23+
'Drupal\Core\DependencyInjection\DependencySerializationTrait does not support private properties.',
24+
16,
25+
'See https://www.drupal.org/node/3110266',
26+
],
27+
[
28+
'Drupal\Core\DependencyInjection\DependencySerializationTrait does not support private properties.',
29+
22,
30+
'See https://www.drupal.org/node/3110266',
31+
],
32+
[
33+
'Read-only properties are incompatible with Drupal\Core\DependencyInjection\DependencySerializationTrait.',
34+
22,
35+
'See https://www.drupal.org/node/3110266',
36+
],
37+
[
38+
'Read-only properties are incompatible with Drupal\Core\DependencyInjection\DependencySerializationTrait.',
39+
28,
40+
'See https://www.drupal.org/node/3110266',
41+
],
42+
[
43+
'Drupal\Core\DependencyInjection\DependencySerializationTrait does not support private properties.',
44+
32,
45+
'See https://www.drupal.org/node/3110266',
46+
],
47+
]
48+
);
49+
}
50+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace DependencySerialization;
4+
5+
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
6+
use Drupal\Core\Entity\EntityTypeManagerInterface;
7+
use Drupal\Core\Form\FormBase;
8+
9+
class Foo {
10+
private EntityTypeManagerInterface $entityTypeManager;
11+
}
12+
13+
class Bar {
14+
use DependencySerializationTrait;
15+
16+
private EntityTypeManagerInterface $entityTypeManager;
17+
}
18+
19+
class Baz {
20+
use DependencySerializationTrait;
21+
22+
private readonly EntityTypeManagerInterface $entityTypeManager;
23+
}
24+
25+
class Qux {
26+
use DependencySerializationTrait;
27+
28+
protected readonly EntityTypeManagerInterface $entityTypeManager;
29+
}
30+
31+
class FooForm extends FormBase {
32+
private EntityTypeManagerInterface $entityTypeManager;
33+
}

0 commit comments

Comments
 (0)