Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ includes:
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
- lib/phpstan/phpstan.neon
- vendor/phpat/phpat/extension.neon
- vendor/phpat/phpat/extension.neon

parameters:
bootstrapFiles:
Expand Down
78 changes: 78 additions & 0 deletions src/ArtyCodingStandard/PHPAt/CleanArchitectureTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace ArtyCodingStandard\PHPAt;

use PHPat\Selector\Selector;
use PHPat\Test\Builder\Rule;
use PHPat\Test\PHPat;

final class CleanArchitectureTest
{
public function testDomainDoesNotDependOnApplication(): Rule
{
return PHPat::rule()
->classes(Selector::inNamespace('App\Domain'))
->shouldNotDependOn()
->classes(Selector::inNamespace('App\Application'))
->because('Domain is the core layer and must remain independent of outer layers');
}

public function testDomainDoesNotDependOnInfrastructure(): Rule
{
return PHPat::rule()
->classes(Selector::inNamespace('App\Domain'))
->shouldNotDependOn()
->classes(Selector::inNamespace('App\Infrastructure'))
->because('Domain must not know about infrastructure concerns (DB, HTTP, etc.)');
}

public function testDomainDoesNotDependOnSymfony(): Rule
{
return PHPat::rule()
->classes(Selector::inNamespace('App\Domain'))
->shouldNotDependOn()
->classes(Selector::inNamespace('Symfony'))
->because('Domain must be framework-agnostic');
}

public function testDomainDoesNotDependOnDoctrine(): Rule
{
return PHPat::rule()
->classes(Selector::inNamespace('App\Domain'))
->shouldNotDependOn()
->classes(Selector::inNamespace('Doctrine'))
->because('Domain must not depend on persistence concerns');
}

public function testApplicationDoesNotDependOnInfrastructure(): Rule
{
return PHPat::rule()
->classes(Selector::inNamespace('App\Application'))
->shouldNotDependOn()
->classes(Selector::inNamespace('App\Infrastructure'))
->because('Application layer must depend on Domain abstractions, not Infrastructure implementations');
}

public function testApplicationDoesNotDependOnSymfony(): Rule
{
return PHPat::rule()
->classes(Selector::inNamespace('App\Application'))
->shouldNotDependOn()
->classes(Selector::inNamespace('Symfony'))
->because('Application use-cases must be framework-agnostic');
}

public function testApplicationDoesNotDependOnDoctrine(): Rule
{
return PHPat::rule()
->classes(Selector::inNamespace('App\Application'))
->shouldNotDependOn()
->classes(Selector::inNamespace('Doctrine'))
->because(
'Application layer must not depend on persistence concerns'
. ' — use Domain repository interfaces instead'
);
}
}
Loading