Skip to content

Commit fab1940

Browse files
added add-shouldOnlyDependOnComponents (#278)
* added add-shouldOnlyDependOnComponents * renamed variable to $componentDependsOnlyOnTheseNamespaces
1 parent f1a2c49 commit fab1940

File tree

5 files changed

+62
-8
lines changed

5 files changed

+62
-8
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,13 @@ return static function (Config $config): void {
286286
->component('Service')->definedBy('App\Service\*')
287287
->component('Repository')->definedBy('App\Repository\*')
288288
->component('Entity')->definedBy('App\Entity\*')
289+
->component('Domain')->definedBy('App\Domain\*')
289290

290291
->where('Controller')->mayDependOnComponents('Service', 'Entity')
291292
->where('Service')->mayDependOnComponents('Repository', 'Entity')
292293
->where('Repository')->mayDependOnComponents('Entity')
293294
->where('Entity')->shouldNotDependOnAnyComponent()
295+
->where('Domain')->shouldOnlyDependOnComponents('Domain')
294296

295297
->rules();
296298

src/RuleBuilders/Architecture/Architecture.php

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,28 @@
33

44
namespace Arkitect\RuleBuilders\Architecture;
55

6+
use Arkitect\Expression\ForClasses\DependsOnlyOnTheseNamespaces;
67
use Arkitect\Expression\ForClasses\NotDependsOnTheseNamespaces;
78
use Arkitect\Expression\ForClasses\ResideInOneOfTheseNamespaces;
89
use Arkitect\Rules\Rule;
910

10-
class Architecture implements Component, DefinedBy, Where, MayDependOnComponents, MayDependOnAnyComponent, ShouldNotDependOnAnyComponent, Rules
11+
class Architecture implements Component, DefinedBy, Where, MayDependOnComponents, MayDependOnAnyComponent, ShouldNotDependOnAnyComponent, ShouldOnlyDependOnComponents, Rules
1112
{
1213
/** @var string */
1314
private $componentName;
1415
/** @var array<string, string> */
1516
private $componentSelectors;
1617
/** @var array<string, string[]> */
1718
private $allowedDependencies;
19+
/** @var array<string, string[]> */
20+
private $componentDependsOnlyOnTheseNamespaces;
1821

1922
private function __construct()
2023
{
2124
$this->componentName = '';
2225
$this->componentSelectors = [];
2326
$this->allowedDependencies = [];
27+
$this->componentDependsOnlyOnTheseNamespaces = [];
2428
}
2529

2630
public static function withComponents(): Component
@@ -38,7 +42,6 @@ public function component(string $name): DefinedBy
3842
public function definedBy(string $selector)
3943
{
4044
$this->componentSelectors[$this->componentName] = $selector;
41-
$this->allowedDependencies[$this->componentName] = [];
4245

4346
return $this;
4447
}
@@ -57,6 +60,13 @@ public function shouldNotDependOnAnyComponent()
5760
return $this;
5861
}
5962

63+
public function shouldOnlyDependOnComponents(string ...$componentNames)
64+
{
65+
$this->componentDependsOnlyOnTheseNamespaces[$this->componentName] = $componentNames;
66+
67+
return $this;
68+
}
69+
6070
public function mayDependOnComponents(string ...$componentNames)
6171
{
6272
$this->allowedDependencies[$this->componentName] = $componentNames;
@@ -76,19 +86,32 @@ public function rules(): iterable
7686
$layerNames = array_keys($this->componentSelectors);
7787

7888
foreach ($this->componentSelectors as $name => $selector) {
79-
$forbiddenComponents = array_diff($layerNames, [$name], $this->allowedDependencies[$name]);
89+
if (isset($this->allowedDependencies[$name])) {
90+
$forbiddenComponents = array_diff($layerNames, [$name], $this->allowedDependencies[$name]);
91+
92+
if (!empty($forbiddenComponents)) {
93+
$forbiddenSelectors = array_map(function (string $componentName): string {
94+
return $this->componentSelectors[$componentName];
95+
}, $forbiddenComponents);
96+
97+
yield Rule::allClasses()
98+
->that(new ResideInOneOfTheseNamespaces($selector))
99+
->should(new NotDependsOnTheseNamespaces(...$forbiddenSelectors))
100+
->because('of component architecture');
101+
}
102+
}
80103

81-
if (empty($forbiddenComponents)) {
104+
if (!isset($this->componentDependsOnlyOnTheseNamespaces[$name])) {
82105
continue;
83106
}
84107

85-
$forbiddenSelectors = array_map(function (string $componentName): string {
108+
$allowedDependencies = array_map(function (string $componentName): string {
86109
return $this->componentSelectors[$componentName];
87-
}, $forbiddenComponents);
110+
}, $this->componentDependsOnlyOnTheseNamespaces[$name]);
88111

89112
yield Rule::allClasses()
90113
->that(new ResideInOneOfTheseNamespaces($selector))
91-
->should(new NotDependsOnTheseNamespaces(...$forbiddenSelectors))
114+
->should(new DependsOnlyOnTheseNamespaces(...$allowedDependencies))
92115
->because('of component architecture');
93116
}
94117
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Arkitect\RuleBuilders\Architecture;
5+
6+
interface ShouldOnlyDependOnComponents
7+
{
8+
/** @return Where&Rules */
9+
public function shouldOnlyDependOnComponents(string ...$componentNames);
10+
}

src/RuleBuilders/Architecture/Where.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55

66
interface Where
77
{
8-
/** @return ShouldNotDependOnAnyComponent&MayDependOnComponents&MayDependOnAnyComponent */
8+
/** @return ShouldNotDependOnAnyComponent&ShouldOnlyDependOnComponents&MayDependOnComponents&MayDependOnAnyComponent */
99
public function where(string $componentName);
1010
}

tests/Unit/Architecture/ArchitectureTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace Arkitect\Tests\Unit\Architecture;
55

6+
use Arkitect\Expression\ForClasses\DependsOnlyOnTheseNamespaces;
67
use Arkitect\Expression\ForClasses\NotDependsOnTheseNamespaces;
78
use Arkitect\Expression\ForClasses\ResideInOneOfTheseNamespaces;
89
use Arkitect\RuleBuilders\Architecture\Architecture;
@@ -37,4 +38,22 @@ public function test_layered_architecture(): void
3738

3839
self::assertEquals($expectedRules, iterator_to_array($rules));
3940
}
41+
42+
public function test_layered_architecture_with_depends_only_on_components(): void
43+
{
44+
$rules = Architecture::withComponents()
45+
->component('Domain')->definedBy('App\*\Domain\*')
46+
->where('Domain')->shouldOnlyDependOnComponents('Domain')
47+
48+
->rules();
49+
50+
$expectedRules = [
51+
Rule::allClasses()
52+
->that(new ResideInOneOfTheseNamespaces('App\*\Domain\*'))
53+
->should(new DependsOnlyOnTheseNamespaces('App\*\Domain\*'))
54+
->because('of component architecture'),
55+
];
56+
57+
self::assertEquals($expectedRules, iterator_to_array($rules));
58+
}
4059
}

0 commit comments

Comments
 (0)