Une application SaaS éducative nécessite une séparation stricte des données entre établissements scolaires. L'architecture multi-tenant par sous-domaine (ecole-alpha.classeo.local) permet cette isolation tout en utilisant une base de code unique. Le choix d'une résolution basée sur les sous-domaines plutôt que sur des headers ou tokens facilite le routage au niveau infrastructure (reverse proxy) et offre une UX plus naturelle où chaque école accède à "son" URL dédiée.
130 lines
5.1 KiB
PHP
130 lines
5.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Architecture;
|
|
|
|
use PHPat\Selector\Selector;
|
|
use PHPat\Test\Builder\BuildStep;
|
|
use PHPat\Test\PHPat;
|
|
|
|
/**
|
|
* Tests ensuring Domain layer purity across all Bounded Contexts.
|
|
*
|
|
* The Domain layer must be pure PHP without framework dependencies.
|
|
* This is critical for DDD architecture and testability.
|
|
*/
|
|
final class DomainPurityTest
|
|
{
|
|
public function test_scolarite_domain_should_not_depend_on_infrastructure(): BuildStep
|
|
{
|
|
return PHPat::rule()
|
|
->classes(Selector::inNamespace('App\Scolarite\Domain'))
|
|
->shouldNotDependOn()
|
|
->classes(
|
|
Selector::inNamespace('App\Scolarite\Infrastructure'),
|
|
Selector::inNamespace('App\Shared\Infrastructure'),
|
|
Selector::inNamespace('Symfony'),
|
|
Selector::inNamespace('Doctrine'),
|
|
Selector::inNamespace('ApiPlatform'),
|
|
)
|
|
->because('Domain must be pure PHP without Infrastructure/framework dependencies');
|
|
}
|
|
|
|
public function test_vie_scolaire_domain_should_not_depend_on_infrastructure(): BuildStep
|
|
{
|
|
return PHPat::rule()
|
|
->classes(Selector::inNamespace('App\VieScolaire\Domain'))
|
|
->shouldNotDependOn()
|
|
->classes(
|
|
Selector::inNamespace('App\VieScolaire\Infrastructure'),
|
|
Selector::inNamespace('App\Shared\Infrastructure'),
|
|
Selector::inNamespace('Symfony'),
|
|
Selector::inNamespace('Doctrine'),
|
|
Selector::inNamespace('ApiPlatform'),
|
|
)
|
|
->because('Domain must be pure PHP without Infrastructure/framework dependencies');
|
|
}
|
|
|
|
public function test_communication_domain_should_not_depend_on_infrastructure(): BuildStep
|
|
{
|
|
return PHPat::rule()
|
|
->classes(Selector::inNamespace('App\Communication\Domain'))
|
|
->shouldNotDependOn()
|
|
->classes(
|
|
Selector::inNamespace('App\Communication\Infrastructure'),
|
|
Selector::inNamespace('App\Shared\Infrastructure'),
|
|
Selector::inNamespace('Symfony'),
|
|
Selector::inNamespace('Doctrine'),
|
|
Selector::inNamespace('ApiPlatform'),
|
|
)
|
|
->because('Domain must be pure PHP without Infrastructure/framework dependencies');
|
|
}
|
|
|
|
public function test_administration_domain_should_not_depend_on_infrastructure(): BuildStep
|
|
{
|
|
return PHPat::rule()
|
|
->classes(Selector::inNamespace('App\Administration\Domain'))
|
|
->shouldNotDependOn()
|
|
->classes(
|
|
Selector::inNamespace('App\Administration\Infrastructure'),
|
|
Selector::inNamespace('App\Shared\Infrastructure'),
|
|
Selector::inNamespace('Symfony'),
|
|
Selector::inNamespace('Doctrine'),
|
|
Selector::inNamespace('ApiPlatform'),
|
|
)
|
|
->because('Domain must be pure PHP without Infrastructure/framework dependencies');
|
|
}
|
|
|
|
public function test_scolarite_domain_should_not_depend_on_application(): BuildStep
|
|
{
|
|
return PHPat::rule()
|
|
->classes(Selector::inNamespace('App\Scolarite\Domain'))
|
|
->shouldNotDependOn()
|
|
->classes(Selector::inNamespace('App\Scolarite\Application'))
|
|
->because('Domain must not know about Application layer');
|
|
}
|
|
|
|
public function test_vie_scolaire_domain_should_not_depend_on_application(): BuildStep
|
|
{
|
|
return PHPat::rule()
|
|
->classes(Selector::inNamespace('App\VieScolaire\Domain'))
|
|
->shouldNotDependOn()
|
|
->classes(Selector::inNamespace('App\VieScolaire\Application'))
|
|
->because('Domain must not know about Application layer');
|
|
}
|
|
|
|
public function test_communication_domain_should_not_depend_on_application(): BuildStep
|
|
{
|
|
return PHPat::rule()
|
|
->classes(Selector::inNamespace('App\Communication\Domain'))
|
|
->shouldNotDependOn()
|
|
->classes(Selector::inNamespace('App\Communication\Application'))
|
|
->because('Domain must not know about Application layer');
|
|
}
|
|
|
|
public function test_administration_domain_should_not_depend_on_application(): BuildStep
|
|
{
|
|
return PHPat::rule()
|
|
->classes(Selector::inNamespace('App\Administration\Domain'))
|
|
->shouldNotDependOn()
|
|
->classes(Selector::inNamespace('App\Administration\Application'))
|
|
->because('Domain must not know about Application layer');
|
|
}
|
|
|
|
public function test_shared_domain_should_be_pure(): BuildStep
|
|
{
|
|
return PHPat::rule()
|
|
->classes(Selector::inNamespace('App\Shared\Domain'))
|
|
->shouldNotDependOn()
|
|
->classes(
|
|
Selector::inNamespace('Symfony'),
|
|
Selector::inNamespace('Doctrine'),
|
|
Selector::inNamespace('ApiPlatform'),
|
|
Selector::inNamespace('App\Shared\Infrastructure'),
|
|
Selector::inNamespace('App\Shared\Application'),
|
|
)
|
|
->because('Shared Domain must be pure PHP');
|
|
}
|
|
}
|