Skip to content

Commit b78ecce

Browse files
authored
Merge pull request #422 from helyakin/feature/addIsReadonlyCheck
feature: Add IsReadonly Expression
2 parents 8f13907 + f16c7f9 commit b78ecce

26 files changed

+348
-0
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,15 @@ $rules[] = Rule::allClasses()
251251
->because('we want to be sure that aggregates are final classes');
252252
```
253253

254+
### Is readonly
255+
256+
```php
257+
$rules[] = Rule::allClasses()
258+
->that(new ResideInOneOfTheseNamespaces('App\Domain\ValueObjects'))
259+
->should(new IsReadonly())
260+
->because('we want to be sure that value objects are readonly classes');
261+
```
262+
254263
### Is interface
255264

256265
```php
@@ -296,6 +305,15 @@ $rules[] = Rule::allClasses()
296305
->because('we want to be sure that our adapters are not final classes');
297306
```
298307

308+
### Is not readonly
309+
310+
```php
311+
$rules[] = Rule::allClasses()
312+
->that(new ResideInOneOfTheseNamespaces('App\Domain\Entity'))
313+
->should(new IsNotReadonly())
314+
->because('we want to be sure that there are no readonly entities');
315+
```
316+
299317
### Is not interface
300318

301319
```php

src/Analyzer/ClassDescription.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ class ClassDescription
2020
/** @var bool */
2121
private $final;
2222

23+
/** @var bool */
24+
private $readonly;
25+
2326
/** @var bool */
2427
private $abstract;
2528

@@ -50,6 +53,7 @@ public function __construct(
5053
array $interfaces,
5154
?FullyQualifiedClassName $extends,
5255
bool $final,
56+
bool $readonly,
5357
bool $abstract,
5458
bool $interface,
5559
bool $trait,
@@ -62,6 +66,7 @@ public function __construct(
6266
$this->interfaces = $interfaces;
6367
$this->extends = $extends;
6468
$this->final = $final;
69+
$this->readonly = $readonly;
6570
$this->abstract = $abstract;
6671
$this->docBlock = $docBlock;
6772
$this->attributes = $attributes;
@@ -130,6 +135,11 @@ public function isFinal(): bool
130135
return $this->final;
131136
}
132137

138+
public function isReadonly(): bool
139+
{
140+
return $this->readonly;
141+
}
142+
133143
public function isAbstract(): bool
134144
{
135145
return $this->abstract;

src/Analyzer/ClassDescriptionBuilder.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ class ClassDescriptionBuilder
2222
/** @var bool */
2323
private $final = false;
2424

25+
/** @var bool */
26+
private $readonly = false;
27+
2528
/** @var bool */
2629
private $abstract = false;
2730

@@ -47,6 +50,7 @@ public function clear(): void
4750
$this->interfaces = [];
4851
$this->extend = null;
4952
$this->final = false;
53+
$this->readonly = false;
5054
$this->abstract = false;
5155
$this->docBlock = [];
5256
$this->attributes = [];
@@ -92,6 +96,13 @@ public function setFinal(bool $final): self
9296
return $this;
9397
}
9498

99+
public function setReadonly(bool $readonly): self
100+
{
101+
$this->readonly = $readonly;
102+
103+
return $this;
104+
}
105+
95106
public function setAbstract(bool $abstract): self
96107
{
97108
$this->abstract = $abstract;
@@ -145,6 +156,7 @@ public function build(): ClassDescription
145156
$this->interfaces,
146157
$this->extend,
147158
$this->final,
159+
$this->readonly,
148160
$this->abstract,
149161
$this->interface,
150162
$this->trait,

src/Analyzer/FileVisitor.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ public function enterNode(Node $node): void
4242
$this->classDescriptionBuilder->setFinal(true);
4343
}
4444

45+
if ($node->isReadonly()) {
46+
$this->classDescriptionBuilder->setReadonly(true);
47+
}
48+
4549
if ($node->isAbstract()) {
4650
$this->classDescriptionBuilder->setAbstract(true);
4751
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Arkitect\Expression\ForClasses;
6+
7+
use Arkitect\Analyzer\ClassDescription;
8+
use Arkitect\Expression\Description;
9+
use Arkitect\Expression\Expression;
10+
use Arkitect\Rules\Violation;
11+
use Arkitect\Rules\ViolationMessage;
12+
use Arkitect\Rules\Violations;
13+
14+
class IsNotReadonly implements Expression
15+
{
16+
public function describe(ClassDescription $theClass, string $because): Description
17+
{
18+
return new Description("{$theClass->getName()} should not be readonly", $because);
19+
}
20+
21+
public function evaluate(ClassDescription $theClass, Violations $violations, string $because): void
22+
{
23+
if (!$theClass->isReadonly()) {
24+
return;
25+
}
26+
27+
$violation = Violation::create(
28+
$theClass->getFQCN(),
29+
ViolationMessage::selfExplanatory($this->describe($theClass, $because))
30+
);
31+
32+
$violations->add($violation);
33+
}
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Arkitect\Expression\ForClasses;
6+
7+
use Arkitect\Analyzer\ClassDescription;
8+
use Arkitect\Expression\Description;
9+
use Arkitect\Expression\Expression;
10+
use Arkitect\Rules\Violation;
11+
use Arkitect\Rules\ViolationMessage;
12+
use Arkitect\Rules\Violations;
13+
14+
class IsReadonly implements Expression
15+
{
16+
public function describe(ClassDescription $theClass, string $because): Description
17+
{
18+
return new Description("{$theClass->getName()} should be readonly", $because);
19+
}
20+
21+
public function evaluate(ClassDescription $theClass, Violations $violations, string $because): void
22+
{
23+
if ($theClass->isReadonly()) {
24+
return;
25+
}
26+
27+
$violation = Violation::create(
28+
$theClass->getFQCN(),
29+
ViolationMessage::selfExplanatory($this->describe($theClass, $because))
30+
);
31+
32+
$violations->add($violation);
33+
}
34+
}

tests/Unit/Expressions/ForClasses/ContainDocBlockLikeTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public function test_it_should_return_true_if_contains_doc_block(): void
2626
false,
2727
false,
2828
false,
29+
false,
2930
['/** */myDocBlock with other information']
3031
);
3132
$because = 'we want to add this rule for our software';
@@ -53,6 +54,7 @@ public function test_it_should_return_true_if_contains_doc_block_without_because
5354
false,
5455
false,
5556
false,
57+
false,
5658
['/** */myDocBlock with other information']
5759
);
5860
$violations = new Violations();
@@ -79,6 +81,7 @@ public function test_it_should_return_false_if_not_contains_doc_block(): void
7981
false,
8082
false,
8183
false,
84+
false,
8285
['/** */myDocBlock with other information']
8386
);
8487
$because = 'we want to add this rule for our software';

tests/Unit/Expressions/ForClasses/ExtendTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public function test_it_should_return_violation_error_if_extend_is_null(): void
8686
false,
8787
false,
8888
false,
89+
false,
8990
false
9091
);
9192

tests/Unit/Expressions/ForClasses/HaveAttributeTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public function test_it_should_return_true_if_contains_doc_block(): void
2626
false,
2727
false,
2828
false,
29+
false,
2930
[],
3031
[FullyQualifiedClassName::fromString('myAttribute')]
3132
);
@@ -54,6 +55,7 @@ public function test_it_should_return_true_if_contains_doc_block_without_because
5455
false,
5556
false,
5657
false,
58+
false,
5759
[],
5860
[FullyQualifiedClassName::fromString('myAttribute')]
5961
);
@@ -81,6 +83,7 @@ public function test_it_should_return_false_if_not_contains_doc_block(): void
8183
false,
8284
false,
8385
false,
86+
false,
8487
[],
8588
[FullyQualifiedClassName::fromString('myAttribute')]
8689
);

tests/Unit/Expressions/ForClasses/ImplementTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public function test_it_should_return_violation_error(): void
2626
false,
2727
false,
2828
false,
29+
false,
2930
false
3031
);
3132

@@ -53,6 +54,7 @@ public function test_it_should_return_true_if_not_depends_on_namespace(): void
5354
false,
5455
false,
5556
false,
57+
false,
5658
false
5759
);
5860
$because = 'we want to add this rule for our software';
@@ -75,6 +77,7 @@ public function test_it_should_return_false_if_depends_on_namespace(): void
7577
false,
7678
false,
7779
false,
80+
false,
7881
false
7982
);
8083
$because = 'we want to add this rule for our software';
@@ -98,6 +101,7 @@ public function test_it_should_check_the_complete_fqcn(): void
98101
false,
99102
false,
100103
false,
104+
false,
101105
false
102106
);
103107
$violations = new Violations();
@@ -118,6 +122,7 @@ public function test_it_should_return_if_is_an_interface(): void
118122
false,
119123
false,
120124
false,
125+
false,
121126
true,
122127
false
123128
);

0 commit comments

Comments
 (0)