expect('Application') ->not->toUse([ 'Presentation', 'Infra', 'Infrastructure', 'App', ]); arch('Application layer does not depend on Illuminate or Symfony frameworks') ->expect('Application') ->not->toUse([ 'Illuminate', 'Symfony', ]); arch('Application layer does not use Laravel helper functions') ->expect('Application') ->not->toUse([ 'abort', 'app', 'auth', 'asset', 'back', 'bcrypt', 'broadcast', 'cache', 'config', 'cookie', 'csrf_token', 'dd', 'dump', 'decrypt', 'dispatch', 'event', 'factory', 'logger', 'redirect', 'request', 'response', 'route', 'session', 'storage', 'url', 'throw_if', 'throw_unless', '__', 'trans', 'trans_choice', 'view', ]); arch('Application layer uses strict types') ->expect('Application') ->toUseStrictTypes(); arch('Application Usecase classes are final and readonly') ->expect(function () { $namespaces = [ 'Application\Arcadia\Usecase', 'Application\Security\Usecases', ]; return array_filter( get_declared_classes(), fn (string $class) => ! interface_exists($class, false) && array_any($namespaces, fn ($ns) => str_starts_with($class, $ns)) ); }) ->classes() ->toBeReadonly() ->toBeFinal(); arch('Classes implementing Shared\DDD\Usecase\Usecase are final and readonly') ->expect(Usecase::class) ->classes() ->toBeReadonly() ->toBeFinal() ->ignoring(Usecase::class); arch('Application Input DTOs implement Shared\DDD\Usecase\Input and are final and readonly') ->expect(Input::class) ->classes() ->toBeReadonly() ->toBeFinal() ->ignoring(Input::class); arch('Application Output DTOs implement Shared\DDD\Usecase\Output and are final and readonly') ->expect(Output::class) ->classes() ->toBeReadonly() ->toBeFinal() ->ignoring(Output::class); arch('Application Health DTOs are final and readonly') ->expect('Application\Health\Dto') ->classes() ->toBeReadonly() ->toBeFinal() ->ignoring([ CheckResult::class, ]); arch('Application Config classes are final and readonly') ->expect([ 'Application\Arcadia\Config', 'Application\Health\Config', 'Application\Security\Config', ]) ->classes() ->toBeReadonly() ->toBeFinal(); arch('Application Port Directories and Repositories contain only interfaces') ->expect([ 'Application\Security\Ports\Directories', 'Application\Security\Ports\Repositories', ]) ->classes() ->toBeInterface(); arch('Application Port Directories extend Shared\DDD\Port\Directory') ->expect('Application\Security\Ports\Directories') ->toExtend(Directory::class); arch('Application Port Repositories extend Shared\DDD\Port\Repository') ->expect('Application\Security\Ports\Repositories') ->toExtend(Repository::class); arch('Application Events implement Shared\DDD\Event\Event and are final and readonly') ->expect('Application\Security\Events') ->toImplement(Event::class) ->classes() ->toBeReadonly() ->toBeFinal(); arch('Application Security Value Objects are final and readonly') ->expect('Application\Security\Models\ValueObjects') ->classes() ->toBeReadonly() ->toBeFinal() ->ignoring([ HttpMethod::class, ]); arch('Application layer must not contain Presenters') ->expect('Application') ->classes() ->not->toHaveSuffix('Presenter'); arch('Application layer must not contain Views') ->expect('Application') ->classes() ->not->toHaveSuffix('View'); });