From e9d084c6406abaea3d5d390e94e0b6e433488cae Mon Sep 17 00:00:00 2001 From: Mohammed Shifreen Date: Sun, 18 Oct 2026 16:45:46 +0530 Subject: [PATCH] Restructure package into a DDD module with Context/* and a shared kernel Move the three sub-contexts (Identity, Authentication, Authorization) under src/Context/* and update all namespaces to Webify\User\Context\*. Relocate application-layer use cases (RegisterUser, OpenSession, VerifyChallenge, AssignRole, CreateRole, etc.) and strategies out of Domain/Service into Application/, where use cases that orchestrate repositories, hashers, ID generators, and event publishers belong. Consolidate value objects that were duplicated and had diverged across contexts into the shared kernel (src/Domain): UserId, UserStatus, and PasswordHash. Add UserStatus::Unverified and remove the now-redundant Authentication copies and UserStatusTranslator. Give the ExtensionInterface entry point a home in src/Infrastructure/Extension/UserExtension and add per-context ServiceDefinitions. Also: - Wire a PHPat DomainSpecification into PHPStan (raised to level 10) - Mirror the src/ layout in test/Unit and add UserExtensionTest - Add docs/refactor.md documenting the refactor and composer.local.json Signed-off-by: Mohammed Shifreen --- .gitignore | 2 + AGENTS.md | 52 +++++ README.md | 1 - composer.local.json | 66 ++++++ .../Infrastructure/.gitkeep => docs/.keep | 0 phpstan.dist.neon | 6 + phpunit.dist.xml | 15 +- src/Application/.gitkeep | 9 + .../Exception/InvalidUserIdException.php | 52 ----- .../Domain/Service/UserStatusTranslator.php | 39 ---- .../Domain/ValueObject/UserId.php | 33 --- .../Session/FindSessionByIdInterface.php | 4 +- .../Session/FindSessionsByUserInterface.php | 4 +- .../Application/Query/Session/Session.php | 2 +- .../Query/Session/SessionCollection.php | 2 +- .../Application}/Service/ChallengeBase.php | 61 ++++-- .../Application}/Service/IssueChallenge.php | 9 +- .../Application}/Service/OpenSession.php | 8 +- .../Application}/Service/PasswordBase.php | 56 +++-- .../Application}/Service/RefreshSession.php | 6 +- .../Application}/Service/RevokeSession.php | 6 +- .../Application}/Service/VerifyChallenge.php | 14 +- .../Strategy/ChallengeCodeStrategy.php | 8 +- .../Strategy/ChallengeTokenStrategy.php | 8 +- .../Domain/Entity/Challenge.php | 17 +- .../Authentication/Domain/Entity/Session.php | 14 +- .../Domain/Event/ChallengeFailed.php | 2 +- .../Domain/Event/ChallengeVerified.php | 2 +- .../Domain/Event/SessionWasOpened.php | 2 +- .../Domain/Event/SessionWasRefreshed.php | 2 +- .../Domain/Event/SessionWasRevoked.php | 2 +- .../AccessTokenGenerationFailedException.php | 2 +- .../AuthenticationFailedException.php | 2 +- .../CannotRefreshSessionException.php | 2 +- ...ChallengeCodeGenerationFailedException.php | 2 +- .../Exception/ChallengeNotFoundException.php | 2 +- ...hallengeTokenGenerationFailedException.php | 2 +- .../ChallengeVerificationFailedException.php | 2 +- .../Exception/InvalidAccessTokenException.php | 2 +- .../InvalidChallengeCodeException.php | 2 +- .../Exception/InvalidChallengeIdException.php | 2 +- .../InvalidChallengeSecretException.php | 2 +- .../InvalidChallengeTokenException.php | 2 +- .../InvalidChallengeTypeException.php | 2 +- .../InvalidRefreshTokenException.php | 2 +- .../Exception/InvalidSessionIdException.php | 2 +- .../InvalidUserCredentialException.php | 2 +- .../RefreshTokenGenerationFailedException.php | 2 +- .../Exception/SessionNotFoundException.php | 2 +- .../Domain/Guard/UserMustBeActive.php | 6 +- .../ChallengeRepositoryInterface.php | 9 +- .../Repository/SessionRepositoryInterface.php | 8 +- .../ChallengeSecretDeliveryInterface.php | 4 +- .../Domain/ValueObject/AccessToken.php | 4 +- .../Domain/ValueObject/AuthenticatedUser.php | 3 +- .../Domain/ValueObject/ChallengeCode.php | 7 +- .../Domain/ValueObject/ChallengeId.php | 4 +- .../ValueObject/ChallengeSecretInterface.php | 2 +- .../Domain/ValueObject/ChallengeStatus.php | 2 +- .../Domain/ValueObject/ChallengeToken.php | 4 +- .../Domain/ValueObject/ChallengeType.php | 2 +- .../Domain/ValueObject/RefreshToken.php | 4 +- .../Domain/ValueObject/SessionId.php | 4 +- .../Container/ServiceDefinitions.php | 36 ++++ .../Exception/StrategyNotFoundException.php | 2 +- .../Service/StrategyRegister.php | 6 +- .../Query/Role/FindAllRolesInterface.php | 2 +- .../Query/Role/FindRoleByIdInterface.php | 4 +- .../Query/Role/FindRoleBySlugInterface.php | 4 +- .../Application/Query/Role/Role.php | 2 +- .../Application/Query/Role/RoleCollection.php | 2 +- .../FindAllRoleAssignmentsInterface.php | 2 +- .../FindRoleAssignmentByIdInterface.php | 4 +- .../FindRoleAssignmentBySubjectInterface.php | 4 +- .../FindRoleAssignmentsByRoleInterface.php | 4 +- .../FindRoleAssignmentsByTenantInterface.php | 4 +- .../Query/RoleAssignment/RoleAssignment.php | 2 +- .../RoleAssignmentCollection.php | 2 +- .../Application}/Service/AssignRole.php | 10 +- .../Application}/Service/CheckAccess.php | 8 +- .../Application}/Service/CreateRole.php | 12 +- .../Application}/Service/RevokeRole.php | 10 +- .../Collection/PermissionCollection.php | 4 +- .../Collection/RoleAssignmentCollection.php | 4 +- .../Authorization/Domain/Entity/Role.php | 10 +- .../Domain/Entity/RoleAssignment.php | 6 +- .../Domain/Event/PermissionGranted.php | 2 +- .../Domain/Event/PermissionRevoked.php | 2 +- .../Domain/Event/RoleAssigned.php | 2 +- .../Domain/Event/RoleCreated.php | 2 +- .../Domain/Event/RoleRevoked.php | 2 +- .../DuplicateRoleAssignmentException.php | 2 +- .../InvalidRoleAssignmentIdException.php | 2 +- .../Exception/InvalidRoleIdException.php | 2 +- .../Exception/InvalidRoleNameException.php | 2 +- .../Exception/InvalidRoleSlugException.php | 2 +- .../Exception/InvalidSubjectIdException.php | 2 +- .../Exception/InvalidTenantIdException.php | 2 +- .../PermissionValidationException.php | 2 +- .../Exception/RoleAlreadyExistsException.php | 2 +- .../RoleAssignmentNotFoundException.php | 2 +- .../Exception/RoleNotFoundException.php | 2 +- .../SystemRoleModificationException.php | 2 +- .../Domain/Guard/DuplicateRoleAssignment.php | 8 +- .../Domain/Guard/RoleAlreadyExists.php | 8 +- .../RoleAssignmentRepositoryInterface.php | 10 +- .../Repository/RoleRepositoryInterface.php | 8 +- .../Domain/Service/Authorization.php | 13 +- .../Domain/ValueObject/Permission.php | 4 +- .../Domain/ValueObject/RoleAssignmentId.php | 4 +- .../Domain/ValueObject/RoleId.php | 4 +- .../Domain/ValueObject/RoleName.php | 4 +- .../Domain/ValueObject/RoleSlug.php | 4 +- .../Domain/ValueObject/SubjectId.php | 4 +- .../Domain/ValueObject/TenantId.php | 4 +- .../Container/ServiceDefinitions.php} | 17 +- .../Query/User/FindAllUserInterface.php | 4 +- .../Query/User/FindUserByEmailInterface.php | 4 +- .../Query/User/FindUserByIdInterface.php | 4 +- .../Identity/Application/Query/User/User.php | 2 +- .../Application/Query/User/UserCollection.php | 2 +- .../Application}/Service/RegisterUser.php | 11 +- .../Application}/Service/UpdateUserEmail.php | 9 +- .../Service/UpdateUserPassword.php | 10 +- .../Identity/Domain/Entity/User.php | 17 +- .../Event/UserDisplayNameWasChanged.php | 2 +- .../Domain/Event/UserEmailWasChanged.php | 2 +- .../Domain/Event/UserPasswordWasChanged.php | 2 +- .../Domain/Event/UserWasActivated.php | 2 +- .../Domain/Event/UserWasDeactivated.php | 2 +- .../Domain/Event/UserWasRegistered.php | 2 +- .../CurrentPasswordNotMatchedException.php | 2 +- .../Exception/EmailMustBeUniqueException.php | 2 +- .../Exception/InvalidDisplayNameException.php | 2 +- .../Exception/InvalidUserEmailException.php | 2 +- .../UserAlreadyActivatedException.php | 2 +- .../UserAlreadyDeactivatedException.php | 2 +- .../UserCannotBeDeactivatedException.php | 2 +- .../Exception/UserNotFoundException.php | 2 +- .../Exception/WeakPasswordException.php | 2 +- .../Domain/Guard/EmailMustBeUnique.php | 8 +- .../Domain/Guard/PasswordMustBeStrong.php | 6 +- .../Identity/Domain/Policy/PasswordPolicy.php | 2 +- .../Repository/UserRepositoryInterface.php | 9 +- .../Domain/ValueObject/DisplayName.php | 4 +- .../Identity/Domain/ValueObject/UserEmail.php | 4 +- .../Container/ServiceDefinitions.php | 36 ++++ .../FailedToHashPasswordException.php | 2 +- .../Infrastructure/Service/PasswordHasher.php | 7 +- .../InvalidPasswordHashException.php | 4 +- .../Exception/InvalidUserIdException.php | 4 +- .../Domain/ValueObject/PasswordHash.php | 25 ++- .../Domain/ValueObject/UserId.php | 7 +- src/Domain/ValueObject/UserStatus.php | 84 ++++++++ .../Domain/ValueObject/UserStatus.php | 48 ----- .../Extension/UserExtension.php | 95 +++++++++ src/Infrastructure/Provider/UserService.php | 37 ++++ .../AuthenticationSpecification.php | 44 ++-- .../AuthorizationSpecification.php | 44 ++-- test/Architecture/DomainSpecification.php | 88 ++++++++ test/Architecture/IdentitySpecification.php | 42 ++-- .../Service/UserStatusTranslatorTest.php | 60 ------ .../Service/ChallengeBaseTest.php | 27 +-- .../Service/IssueChallengeTest.php | 11 +- .../Application}/Service/OpenSessionTest.php | 11 +- .../Application}/Service/PasswordBaseTest.php | 27 +-- .../Service/RefreshSessionTest.php | 13 +- .../Service/RevokeSessionTest.php | 13 +- .../Service/VerifyChallengeTest.php | 19 +- .../Strategy/ChallengeCodeStrategyTest.php | 13 +- .../Strategy/ChallengeTokenStrategyTest.php | 13 +- .../Domain/Entity/ChallengeTest.php | 18 +- .../Domain/Entity/SessionTest.php | 11 +- .../Domain/Guard/UserMustBeActiveTest.php | 8 +- .../Domain/ValueObject/AccessTokenTest.php | 6 +- .../Domain/ValueObject/ChallengeCodeTest.php | 6 +- .../Domain/ValueObject/ChallengeIdTest.php | 6 +- .../ValueObject/ChallengeStatusTest.php | 4 +- .../Domain/ValueObject/ChallengeTokenTest.php | 6 +- .../Domain/ValueObject/ChallengeTypeTest.php | 4 +- .../Domain/ValueObject/RefreshTokenTest.php | 6 +- .../Domain/ValueObject/SessionIdTest.php | 6 +- .../Service/StrategyRegisterTest.php | 6 +- .../Application}/Service/AssignRoleTest.php | 16 +- .../Application}/Service/CheckAccessTest.php | 13 +- .../Application}/Service/CreateRoleTest.php | 14 +- .../Application}/Service/RevokeRoleTest.php | 14 +- .../Domain/Entity/RoleAssignmentTest.php | 8 +- .../Authorization/Domain/Entity/RoleTest.php | 10 +- .../Guard/DuplicateRoleAssignmentTest.php | 10 +- .../Domain/Guard/RoleAlreadyExistsTest.php | 10 +- .../Domain/Service/AuthorizationTest.php | 24 +-- .../Domain/ValueObject/PermissionTest.php | 6 +- .../ValueObject/RoleAssignmentIdTest.php | 6 +- .../Domain/ValueObject/RoleIdTest.php | 6 +- .../Domain/ValueObject/RoleNameTest.php | 6 +- .../Domain/ValueObject/RoleSlugTest.php | 6 +- .../Domain/ValueObject/SubjectIdTest.php | 6 +- .../Domain/ValueObject/TenantIdTest.php | 6 +- .../Application}/Service/RegisterUserTest.php | 16 +- .../Service/UpdateUserEmailTest.php | 19 +- .../Service/UpdateUserPasswordTest.php | 25 +-- .../Identity/Domain/Entity/UserTest.php | 20 +- .../Domain/Guard/EmailMustBeUniqueTest.php | 10 +- .../Domain/Guard/PasswordMustBeStrongTest.php | 8 +- .../Domain/ValueObject/DisplayNameTest.php | 6 +- .../Domain/ValueObject/UserEmailTest.php | 6 +- .../Service/PasswordHasherTest.php | 4 +- .../Domain/ValueObject/PasswordHashTest.php | 64 +++++- .../Domain/ValueObject/UserIdTest.php | 6 +- .../Domain/ValueObject/UserStatusTest.php | 185 ++++++++++++++++ .../Domain/ValueObject/UserStatusTest.php | 102 --------- .../Extension/UserExtensionTest.php | 201 ++++++++++++++++++ 213 files changed, 1645 insertions(+), 1048 deletions(-) create mode 100644 AGENTS.md create mode 100644 composer.local.json rename src/Authorization/Infrastructure/.gitkeep => docs/.keep (100%) create mode 100644 src/Application/.gitkeep delete mode 100644 src/Authentication/Domain/Exception/InvalidUserIdException.php delete mode 100644 src/Authentication/Domain/Service/UserStatusTranslator.php delete mode 100644 src/Authentication/Domain/ValueObject/UserId.php rename src/{ => Context}/Authentication/Application/Query/Session/FindSessionByIdInterface.php (83%) rename src/{ => Context}/Authentication/Application/Query/Session/FindSessionsByUserInterface.php (89%) rename src/{ => Context}/Authentication/Application/Query/Session/Session.php (89%) rename src/{ => Context}/Authentication/Application/Query/Session/SessionCollection.php (89%) rename src/{Authentication/Domain => Context/Authentication/Application}/Service/ChallengeBase.php (72%) rename src/{Authentication/Domain => Context/Authentication/Application}/Service/IssueChallenge.php (89%) rename src/{Authentication/Domain => Context/Authentication/Application}/Service/OpenSession.php (84%) rename src/{Authentication/Domain => Context/Authentication/Application}/Service/PasswordBase.php (64%) rename src/{Authentication/Domain => Context/Authentication/Application}/Service/RefreshSession.php (88%) rename src/{Authentication/Domain => Context/Authentication/Application}/Service/RevokeSession.php (85%) rename src/{Authentication/Domain => Context/Authentication/Application}/Service/VerifyChallenge.php (79%) rename src/{Authentication/Domain => Context/Authentication/Application}/Strategy/ChallengeCodeStrategy.php (81%) rename src/{Authentication/Domain => Context/Authentication/Application}/Strategy/ChallengeTokenStrategy.php (81%) rename src/{ => Context}/Authentication/Domain/Entity/Challenge.php (90%) rename src/{ => Context}/Authentication/Domain/Entity/Session.php (92%) rename src/{ => Context}/Authentication/Domain/Event/ChallengeFailed.php (94%) rename src/{ => Context}/Authentication/Domain/Event/ChallengeVerified.php (94%) rename src/{ => Context}/Authentication/Domain/Event/SessionWasOpened.php (94%) rename src/{ => Context}/Authentication/Domain/Event/SessionWasRefreshed.php (94%) rename src/{ => Context}/Authentication/Domain/Event/SessionWasRevoked.php (94%) rename src/{ => Context}/Authentication/Domain/Exception/AccessTokenGenerationFailedException.php (96%) rename src/{ => Context}/Authentication/Domain/Exception/AuthenticationFailedException.php (98%) rename src/{ => Context}/Authentication/Domain/Exception/CannotRefreshSessionException.php (95%) rename src/{ => Context}/Authentication/Domain/Exception/ChallengeCodeGenerationFailedException.php (96%) rename src/{ => Context}/Authentication/Domain/Exception/ChallengeNotFoundException.php (96%) rename src/{ => Context}/Authentication/Domain/Exception/ChallengeTokenGenerationFailedException.php (96%) rename src/{ => Context}/Authentication/Domain/Exception/ChallengeVerificationFailedException.php (97%) rename src/{ => Context}/Authentication/Domain/Exception/InvalidAccessTokenException.php (95%) rename src/{ => Context}/Authentication/Domain/Exception/InvalidChallengeCodeException.php (95%) rename src/{ => Context}/Authentication/Domain/Exception/InvalidChallengeIdException.php (95%) rename src/{ => Context}/Authentication/Domain/Exception/InvalidChallengeSecretException.php (95%) rename src/{ => Context}/Authentication/Domain/Exception/InvalidChallengeTokenException.php (95%) rename src/{ => Context}/Authentication/Domain/Exception/InvalidChallengeTypeException.php (95%) rename src/{ => Context}/Authentication/Domain/Exception/InvalidRefreshTokenException.php (95%) rename src/{ => Context}/Authentication/Domain/Exception/InvalidSessionIdException.php (95%) rename src/{ => Context}/Authentication/Domain/Exception/InvalidUserCredentialException.php (95%) rename src/{ => Context}/Authentication/Domain/Exception/RefreshTokenGenerationFailedException.php (96%) rename src/{ => Context}/Authentication/Domain/Exception/SessionNotFoundException.php (97%) rename src/{ => Context}/Authentication/Domain/Guard/UserMustBeActive.php (78%) rename src/{ => Context}/Authentication/Domain/Repository/ChallengeRepositoryInterface.php (80%) rename src/{ => Context}/Authentication/Domain/Repository/SessionRepositoryInterface.php (81%) rename src/{ => Context}/Authentication/Domain/Service/ChallengeSecretDeliveryInterface.php (88%) rename src/{ => Context}/Authentication/Domain/ValueObject/AccessToken.php (86%) rename src/{ => Context}/Authentication/Domain/ValueObject/AuthenticatedUser.php (93%) rename src/{ => Context}/Authentication/Domain/ValueObject/ChallengeCode.php (92%) rename src/{ => Context}/Authentication/Domain/ValueObject/ChallengeId.php (83%) rename src/{ => Context}/Authentication/Domain/ValueObject/ChallengeSecretInterface.php (89%) rename src/{ => Context}/Authentication/Domain/ValueObject/ChallengeStatus.php (91%) rename src/{ => Context}/Authentication/Domain/ValueObject/ChallengeToken.php (87%) rename src/{ => Context}/Authentication/Domain/ValueObject/ChallengeType.php (92%) rename src/{ => Context}/Authentication/Domain/ValueObject/RefreshToken.php (85%) rename src/{ => Context}/Authentication/Domain/ValueObject/SessionId.php (83%) create mode 100644 src/Context/Authentication/Infrastructure/Container/ServiceDefinitions.php rename src/{ => Context}/Authentication/Infrastructure/Exception/StrategyNotFoundException.php (95%) rename src/{ => Context}/Authentication/Infrastructure/Service/StrategyRegister.php (88%) rename src/{ => Context}/Authorization/Application/Query/Role/FindAllRolesInterface.php (89%) rename src/{ => Context}/Authorization/Application/Query/Role/FindRoleByIdInterface.php (82%) rename src/{ => Context}/Authorization/Application/Query/Role/FindRoleBySlugInterface.php (82%) rename src/{ => Context}/Authorization/Application/Query/Role/Role.php (92%) rename src/{ => Context}/Authorization/Application/Query/Role/RoleCollection.php (89%) rename src/{ => Context}/Authorization/Application/Query/RoleAssignment/FindAllRoleAssignmentsInterface.php (91%) rename src/{ => Context}/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentByIdInterface.php (79%) rename src/{ => Context}/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentBySubjectInterface.php (85%) rename src/{ => Context}/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByRoleInterface.php (84%) rename src/{ => Context}/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByTenantInterface.php (84%) rename src/{ => Context}/Authorization/Application/Query/RoleAssignment/RoleAssignment.php (89%) rename src/{ => Context}/Authorization/Application/Query/RoleAssignment/RoleAssignmentCollection.php (88%) rename src/{Authorization/Domain => Context/Authorization/Application}/Service/AssignRole.php (86%) rename src/{Authorization/Domain => Context/Authorization/Application}/Service/CheckAccess.php (89%) rename src/{Authorization/Domain => Context/Authorization/Application}/Service/CreateRole.php (86%) rename src/{Authorization/Domain => Context/Authorization/Application}/Service/RevokeRole.php (83%) rename src/{ => Context}/Authorization/Domain/Collection/PermissionCollection.php (81%) rename src/{ => Context}/Authorization/Domain/Collection/RoleAssignmentCollection.php (82%) rename src/{ => Context}/Authorization/Domain/Entity/Role.php (89%) rename src/{ => Context}/Authorization/Domain/Entity/RoleAssignment.php (94%) rename src/{ => Context}/Authorization/Domain/Event/PermissionGranted.php (95%) rename src/{ => Context}/Authorization/Domain/Event/PermissionRevoked.php (95%) rename src/{ => Context}/Authorization/Domain/Event/RoleAssigned.php (94%) rename src/{ => Context}/Authorization/Domain/Event/RoleCreated.php (96%) rename src/{ => Context}/Authorization/Domain/Event/RoleRevoked.php (94%) rename src/{ => Context}/Authorization/Domain/Exception/DuplicateRoleAssignmentException.php (96%) rename src/{ => Context}/Authorization/Domain/Exception/InvalidRoleAssignmentIdException.php (96%) rename src/{ => Context}/Authorization/Domain/Exception/InvalidRoleIdException.php (95%) rename src/{ => Context}/Authorization/Domain/Exception/InvalidRoleNameException.php (95%) rename src/{ => Context}/Authorization/Domain/Exception/InvalidRoleSlugException.php (96%) rename src/{ => Context}/Authorization/Domain/Exception/InvalidSubjectIdException.php (95%) rename src/{ => Context}/Authorization/Domain/Exception/InvalidTenantIdException.php (95%) rename src/{ => Context}/Authorization/Domain/Exception/PermissionValidationException.php (95%) rename src/{ => Context}/Authorization/Domain/Exception/RoleAlreadyExistsException.php (95%) rename src/{ => Context}/Authorization/Domain/Exception/RoleAssignmentNotFoundException.php (95%) rename src/{ => Context}/Authorization/Domain/Exception/RoleNotFoundException.php (96%) rename src/{ => Context}/Authorization/Domain/Exception/SystemRoleModificationException.php (95%) rename src/{ => Context}/Authorization/Domain/Guard/DuplicateRoleAssignment.php (79%) rename src/{ => Context}/Authorization/Domain/Guard/RoleAlreadyExists.php (77%) rename src/{ => Context}/Authorization/Domain/Repository/RoleAssignmentRepositoryInterface.php (85%) rename src/{ => Context}/Authorization/Domain/Repository/RoleRepositoryInterface.php (78%) rename src/{ => Context}/Authorization/Domain/Service/Authorization.php (89%) rename src/{ => Context}/Authorization/Domain/ValueObject/Permission.php (96%) rename src/{ => Context}/Authorization/Domain/ValueObject/RoleAssignmentId.php (82%) rename src/{ => Context}/Authorization/Domain/ValueObject/RoleId.php (82%) rename src/{ => Context}/Authorization/Domain/ValueObject/RoleName.php (92%) rename src/{ => Context}/Authorization/Domain/ValueObject/RoleSlug.php (94%) rename src/{ => Context}/Authorization/Domain/ValueObject/SubjectId.php (82%) rename src/{ => Context}/Authorization/Domain/ValueObject/TenantId.php (82%) rename src/{Authentication/Domain/ValueObject/UserStatus.php => Context/Authorization/Infrastructure/Container/ServiceDefinitions.php} (53%) rename src/{ => Context}/Identity/Application/Query/User/FindAllUserInterface.php (79%) rename src/{ => Context}/Identity/Application/Query/User/FindUserByEmailInterface.php (84%) rename src/{ => Context}/Identity/Application/Query/User/FindUserByIdInterface.php (86%) rename src/{ => Context}/Identity/Application/Query/User/User.php (94%) rename src/{ => Context}/Identity/Application/Query/User/UserCollection.php (90%) rename src/{Identity/Domain => Context/Identity/Application}/Service/RegisterUser.php (83%) rename src/{Identity/Domain => Context/Identity/Application}/Service/UpdateUserEmail.php (82%) rename src/{Identity/Domain => Context/Identity/Application}/Service/UpdateUserPassword.php (85%) rename src/{ => Context}/Identity/Domain/Entity/User.php (90%) rename src/{ => Context}/Identity/Domain/Event/UserDisplayNameWasChanged.php (94%) rename src/{ => Context}/Identity/Domain/Event/UserEmailWasChanged.php (94%) rename src/{ => Context}/Identity/Domain/Event/UserPasswordWasChanged.php (94%) rename src/{ => Context}/Identity/Domain/Event/UserWasActivated.php (94%) rename src/{ => Context}/Identity/Domain/Event/UserWasDeactivated.php (94%) rename src/{ => Context}/Identity/Domain/Event/UserWasRegistered.php (94%) rename src/{ => Context}/Identity/Domain/Exception/CurrentPasswordNotMatchedException.php (96%) rename src/{ => Context}/Identity/Domain/Exception/EmailMustBeUniqueException.php (96%) rename src/{ => Context}/Identity/Domain/Exception/InvalidDisplayNameException.php (96%) rename src/{ => Context}/Identity/Domain/Exception/InvalidUserEmailException.php (96%) rename src/{ => Context}/Identity/Domain/Exception/UserAlreadyActivatedException.php (96%) rename src/{ => Context}/Identity/Domain/Exception/UserAlreadyDeactivatedException.php (96%) rename src/{ => Context}/Identity/Domain/Exception/UserCannotBeDeactivatedException.php (96%) rename src/{ => Context}/Identity/Domain/Exception/UserNotFoundException.php (96%) rename src/{ => Context}/Identity/Domain/Exception/WeakPasswordException.php (98%) rename src/{ => Context}/Identity/Domain/Guard/EmailMustBeUnique.php (76%) rename src/{ => Context}/Identity/Domain/Guard/PasswordMustBeStrong.php (90%) rename src/{ => Context}/Identity/Domain/Policy/PasswordPolicy.php (98%) rename src/{ => Context}/Identity/Domain/Repository/UserRepositoryInterface.php (79%) rename src/{ => Context}/Identity/Domain/ValueObject/DisplayName.php (93%) rename src/{ => Context}/Identity/Domain/ValueObject/UserEmail.php (85%) create mode 100644 src/Context/Identity/Infrastructure/Container/ServiceDefinitions.php rename src/{ => Context}/Identity/Infrastructure/Exception/FailedToHashPasswordException.php (95%) rename src/{ => Context}/Identity/Infrastructure/Service/PasswordHasher.php (81%) rename src/{Identity => }/Domain/Exception/InvalidPasswordHashException.php (91%) rename src/{Identity => }/Domain/Exception/InvalidUserIdException.php (91%) rename src/{Identity => }/Domain/ValueObject/PasswordHash.php (55%) rename src/{Identity => }/Domain/ValueObject/UserId.php (71%) create mode 100644 src/Domain/ValueObject/UserStatus.php delete mode 100644 src/Identity/Domain/ValueObject/UserStatus.php create mode 100644 src/Infrastructure/Extension/UserExtension.php create mode 100644 src/Infrastructure/Provider/UserService.php create mode 100644 test/Architecture/DomainSpecification.php delete mode 100644 test/Unit/Authentication/Domain/Service/UserStatusTranslatorTest.php rename test/Unit/{Authentication/Domain => Context/Authentication/Application}/Service/ChallengeBaseTest.php (93%) rename test/Unit/{Authentication/Domain => Context/Authentication/Application}/Service/IssueChallengeTest.php (88%) rename test/Unit/{Authentication/Domain => Context/Authentication/Application}/Service/OpenSessionTest.php (88%) rename test/Unit/{Authentication/Domain => Context/Authentication/Application}/Service/PasswordBaseTest.php (92%) rename test/Unit/{Authentication/Domain => Context/Authentication/Application}/Service/RefreshSessionTest.php (87%) rename test/Unit/{Authentication/Domain => Context/Authentication/Application}/Service/RevokeSessionTest.php (86%) rename test/Unit/{Authentication/Domain => Context/Authentication/Application}/Service/VerifyChallengeTest.php (89%) rename test/Unit/{Authentication/Domain => Context/Authentication/Application}/Strategy/ChallengeCodeStrategyTest.php (89%) rename test/Unit/{Authentication/Domain => Context/Authentication/Application}/Strategy/ChallengeTokenStrategyTest.php (89%) rename test/Unit/{ => Context}/Authentication/Domain/Entity/ChallengeTest.php (93%) rename test/Unit/{ => Context}/Authentication/Domain/Entity/SessionTest.php (92%) rename test/Unit/{ => Context}/Authentication/Domain/Guard/UserMustBeActiveTest.php (81%) rename test/Unit/{ => Context}/Authentication/Domain/ValueObject/AccessTokenTest.php (93%) rename test/Unit/{ => Context}/Authentication/Domain/ValueObject/ChallengeCodeTest.php (93%) rename test/Unit/{ => Context}/Authentication/Domain/ValueObject/ChallengeIdTest.php (85%) rename test/Unit/{ => Context}/Authentication/Domain/ValueObject/ChallengeStatusTest.php (93%) rename test/Unit/{ => Context}/Authentication/Domain/ValueObject/ChallengeTokenTest.php (93%) rename test/Unit/{ => Context}/Authentication/Domain/ValueObject/ChallengeTypeTest.php (93%) rename test/Unit/{ => Context}/Authentication/Domain/ValueObject/RefreshTokenTest.php (93%) rename test/Unit/{ => Context}/Authentication/Domain/ValueObject/SessionIdTest.php (84%) rename test/Unit/{ => Context}/Authentication/Infrastructure/Service/StrategyRegisterTest.php (92%) rename test/Unit/{Authorization/Domain => Context/Authorization/Application}/Service/AssignRoleTest.php (91%) rename test/Unit/{Authorization/Domain => Context/Authorization/Application}/Service/CheckAccessTest.php (95%) rename test/Unit/{Authorization/Domain => Context/Authorization/Application}/Service/CreateRoleTest.php (93%) rename test/Unit/{Authorization/Domain => Context/Authorization/Application}/Service/RevokeRoleTest.php (89%) rename test/Unit/{ => Context}/Authorization/Domain/Entity/RoleAssignmentTest.php (95%) rename test/Unit/{ => Context}/Authorization/Domain/Entity/RoleTest.php (92%) rename test/Unit/{ => Context}/Authorization/Domain/Guard/DuplicateRoleAssignmentTest.php (82%) rename test/Unit/{ => Context}/Authorization/Domain/Guard/RoleAlreadyExistsTest.php (82%) rename test/Unit/{ => Context}/Authorization/Domain/Service/AuthorizationTest.php (97%) rename test/Unit/{ => Context}/Authorization/Domain/ValueObject/PermissionTest.php (96%) rename test/Unit/{ => Context}/Authorization/Domain/ValueObject/RoleAssignmentIdTest.php (92%) rename test/Unit/{ => Context}/Authorization/Domain/ValueObject/RoleIdTest.php (91%) rename test/Unit/{ => Context}/Authorization/Domain/ValueObject/RoleNameTest.php (90%) rename test/Unit/{ => Context}/Authorization/Domain/ValueObject/RoleSlugTest.php (96%) rename test/Unit/{ => Context}/Authorization/Domain/ValueObject/SubjectIdTest.php (92%) rename test/Unit/{ => Context}/Authorization/Domain/ValueObject/TenantIdTest.php (92%) rename test/Unit/{Identity/Domain => Context/Identity/Application}/Service/RegisterUserTest.php (87%) rename test/Unit/{Identity/Domain => Context/Identity/Application}/Service/UpdateUserEmailTest.php (88%) rename test/Unit/{Identity/Domain => Context/Identity/Application}/Service/UpdateUserPasswordTest.php (85%) rename test/Unit/{ => Context}/Identity/Domain/Entity/UserTest.php (88%) rename test/Unit/{ => Context}/Identity/Domain/Guard/EmailMustBeUniqueTest.php (83%) rename test/Unit/{ => Context}/Identity/Domain/Guard/PasswordMustBeStrongTest.php (91%) rename test/Unit/{ => Context}/Identity/Domain/ValueObject/DisplayNameTest.php (94%) rename test/Unit/{ => Context}/Identity/Domain/ValueObject/UserEmailTest.php (84%) rename test/Unit/{Identity/Domain => Context/Identity/Infrastructure}/Service/PasswordHasherTest.php (95%) rename test/Unit/{Identity => }/Domain/ValueObject/PasswordHashTest.php (55%) rename test/Unit/{Identity => }/Domain/ValueObject/UserIdTest.php (86%) create mode 100644 test/Unit/Domain/ValueObject/UserStatusTest.php delete mode 100644 test/Unit/Identity/Domain/ValueObject/UserStatusTest.php create mode 100644 test/Unit/Infrastructure/Extension/UserExtensionTest.php diff --git a/.gitignore b/.gitignore index 347b328..38d1be4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ Thumbs.db # composer /vendor/ composer.phar +composer.local.json +composer.local.lock # Mac DS_Store Files .DS_Store diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..fe010ed --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,52 @@ +# WebifyCMS User Extension + +Package `webifycms/ext-user` (composer type `webifycms-extension`). Manages the +**user bounded context** — Identity, Authentication, and Authorization. An +extension of WebifyCMS (not a standalone app). Requires `webifycms/ext-base`. + +## Layout + +``` +src/ + Context/{Context}/{Layer}/{Part} + Domain/{Exception,ValueObject} # shared kernel, below every context + Application/ # cross-context use cases, as they emerge + Infrastructure/Extension/ + +Contexts: Identity, Authentication, Authorization +Layers: Application, Domain, Infrastructure +Parts: e.g. Application/{Query,Service,Strategy}, + Domain/{Collection,Entity,Event,Exception,Guard,Policy,Repository,Service,ValueObject} +``` + +- `Identity/` — user identity/policies +- `Authentication/` — login/registration, guards, strategies +- `Authorization/` — roles, permissions, role assignment (user bounded context) +- `src/Domain/` — shared kernel: `UserId`, `UserStatus`, `PasswordHash` and their + exceptions. It sits below every context and must not depend on `Context`, `Application`, + or `Infrastructure` — enforced by `test/Architecture/DomainSpecification.php`. +- `src/Infrastructure/Extension/` — the `ExtensionInterface` entry point. It spans all three + contexts, which is why it cannot live inside any one of them. + +## Conventions + +- Namespace `Webify\User\*` (autoload `Webify\User\` → `src/`); tests `Webify\User\Test\` → `test/`. +- Follow Clean Architecture layering; Domain defines interfaces, Infrastructure implements them. + Domain must not depend on Application or Infrastructure — anything that orchestrates + repositories, event publishers, hashers, or ID generators is a use case and belongs in + `Application`. Enforced per context by the PHPat specs in `test/Architecture/`. +- Shared-kernel value objects are consumed across contexts directly; do not re-declare a + per-context copy. +- Extensions register themselves via the ext-base extension/service-provider contracts + (see `extensions/ext-base/AGENTS.md`). +- A ServiceProvider bootstrap for the context lives under `src/{Context}/Infrastructure/Service/`. + +## Verification + +```bash +composer test # PHPUnit +composer analyse # PHPStan level 10 + PHPat architecture rules +composer sniff # PHP-CS-Fixer dry-run +composer code-check # analyse + sniff +composer code-format # PHP-CS-Fixer fix +``` \ No newline at end of file diff --git a/README.md b/README.md index c1ab790..8b4f944 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![PHP Version](https://img.shields.io/badge/PHP-8.4%2B-blue)](https://www.php.net) [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE.md) -[![Version](https://img.shields.io/badge/version-0.1.0--alpha-orange)](https://github.com/webifycms/ext-base) [![Type](https://img.shields.io/badge/type-extension-green)]() > 👋 Hey there! We're still in the early stage of development, so you may not find all the features just yet. diff --git a/composer.local.json b/composer.local.json new file mode 100644 index 0000000..1c03e58 --- /dev/null +++ b/composer.local.json @@ -0,0 +1,66 @@ +{ + "name": "webifycms/ext-user", + "description": "The WebifyCMS user extension handles all user-related tasks, including user management, profile and account management, login, and registration.", + "type": "webifycms-extension", + "authors": [ + { + "name": "Mohammed Shifreen", + "email": "mshifreen@gmail.com" + } + ], + "minimum-stability": "dev", + "prefer-stable": true, + "require": { + "php": ">=8.4", + "webifycms/ext-base": "*" + }, + "require-dev": { + "webifycms/dev-tools": "*", + "phpunit/phpunit": "^13.1", + "fakerphp/faker": "^1.24", + "phpat/phpat": "^0.12", + "filp/whoops": "^2.18", + "middlewares/whoops": "^2.1", + "roave/security-advisories": "dev-latest" + }, + "autoload": { + "psr-4": { + "Webify\\User\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Webify\\User\\Test\\": "test/" + } + }, + "optimize-autoloader": true, + "repositories": [ + { + "type": "composer", + "url": "https://asset-packagist.org" + }, + { + "type": "path", + "url": "../ext-base" + }, + { + "type": "path", + "url": "../../dev-tools" + } + ], + "scripts": { + "analyse": [ + "phpstan" + ], + "sniff": [ + "php-cs-fixer fix --show-progress=dots --diff --dry-run" + ], + "test": [ + "phpunit test" + ], + "code-check": ["@analyse", "@sniff"], + "code-format": [ + "php-cs-fixer fix --show-progress=dots" + ] + } +} \ No newline at end of file diff --git a/src/Authorization/Infrastructure/.gitkeep b/docs/.keep similarity index 100% rename from src/Authorization/Infrastructure/.gitkeep rename to docs/.keep diff --git a/phpstan.dist.neon b/phpstan.dist.neon index 9e882d3..fd0a550 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -8,8 +8,10 @@ includes: - vendor/webifycms/dev-tools/phpstan-default.neon + - vendor/phpat/phpat/extension.neon parameters: + level: 10 paths: - src - test @@ -18,6 +20,10 @@ parameters: reportUnmatchedIgnoredErrors: false services: + - + class: Webify\User\Test\Architecture\DomainSpecification + tags: + - phpat.test - class: Webify\User\Test\Architecture\AuthenticationSpecification tags: diff --git a/phpunit.dist.xml b/phpunit.dist.xml index 0b7e9cd..fc63bb9 100644 --- a/phpunit.dist.xml +++ b/phpunit.dist.xml @@ -3,7 +3,6 @@ xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" bootstrap="vendor/autoload.php" cacheDirectory=".phpunit.cache" - executionOrder="depends,defects" requireCoverageMetadata="true" beStrictAboutCoverageMetadata="true" beStrictAboutOutputDuringTests="true" @@ -16,16 +15,24 @@ testdox="true" > + + test/Unit/Domain + + - test/User/Authentication + test/Unit/Context/Authentication - test/User/Authorization + test/Unit/Context/Authorization - test/User/Identity + test/Unit/Context/Identity + + + + test/Unit/Infrastructure diff --git a/src/Application/.gitkeep b/src/Application/.gitkeep new file mode 100644 index 0000000..45edb4e --- /dev/null +++ b/src/Application/.gitkeep @@ -0,0 +1,9 @@ +# The top-level `Application` layer is reserved for cross-context use cases. +# +# Nothing lives here yet by design: cross-context transactions (for example a use case that +# registers a user and then opens a session) have not emerged. Add use cases under +# `src/Application/{Part}/` as they do. +# +# This directory is referenced by `DomainSpecification`, which forbids the shared +# kernel in `src/Domain` from depending on it. It is a guarded empty namespace, not a +# forgotten one. \ No newline at end of file diff --git a/src/Authentication/Domain/Exception/InvalidUserIdException.php b/src/Authentication/Domain/Exception/InvalidUserIdException.php deleted file mode 100644 index 1bae4c7..0000000 --- a/src/Authentication/Domain/Exception/InvalidUserIdException.php +++ /dev/null @@ -1,52 +0,0 @@ - - */ -declare(strict_types=1); - -namespace Webify\User\Authentication\Domain\Exception; - -use InvalidArgumentException; -use Webify\Base\Contract\Exception\TranslatableExceptionInterface; -use Webify\Base\Contract\Translation\ExceptionTranslation; - -/** - * Exception thrown when an invalid user ID is encountered. - */ -final class InvalidUserIdException extends InvalidArgumentException implements TranslatableExceptionInterface -{ - /** - * Private constructor enforces the use of the factory methods to initiate this exception. - * - * @param ExceptionTranslation $translation the translation object for this exception - * @param string $message the exception message (optional) - */ - private function __construct( - public readonly ExceptionTranslation $translation, - string $message = '' - ) { - parent::__construct($message); - } - - /** - * Factory method to initiate this with a default message. - */ - public static function forInvalidId(string $id): InvalidUserIdException - { - return new self( - new ExceptionTranslation( - 'user.authentication', - 'invalid_user_id', - ['id' => $id] - ), - sprintf('The authentication user ID "%s" is invalid.', $id) - ); - } -} diff --git a/src/Authentication/Domain/Service/UserStatusTranslator.php b/src/Authentication/Domain/Service/UserStatusTranslator.php deleted file mode 100644 index 18ce658..0000000 --- a/src/Authentication/Domain/Service/UserStatusTranslator.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ -declare(strict_types=1); - -namespace Webify\User\Authentication\Domain\Service; - -use Webify\User\Authentication\Domain\ValueObject\UserStatus; - -/** - * UserStatusTranslator service handles the translation of the user status. - * - * Translates the user status string to a UserStatus enum value. - */ -final class UserStatusTranslator -{ - /** - * Translates a given user status string to a corresponding Authentication known status. - * - * @param string $status the user-provided status input, such as 'active' - * - * @return UserStatus the translated status corresponding to the input, or an empty string if no match is found - */ - public function translate(string $status): UserStatus - { - return match ($status) { - 'active' => UserStatus::Active, - default => UserStatus::Unverified, - }; - } -} diff --git a/src/Authentication/Domain/ValueObject/UserId.php b/src/Authentication/Domain/ValueObject/UserId.php deleted file mode 100644 index 8449cf6..0000000 --- a/src/Authentication/Domain/ValueObject/UserId.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -declare(strict_types=1); - -namespace Webify\User\Authentication\Domain\ValueObject; - -use Webify\Base\Domain\ValueObject\AggregateId; -use Webify\User\Authentication\Domain\Exception\InvalidUserIdException; - -/** - * User ID value object. - */ -final readonly class UserId extends AggregateId -{ - /** - * Throws an exception for an invalid user ID. - * - * @throws InvalidUserIdException if the user ID is invalid - */ - protected function throwException(string $value): never - { - throw InvalidUserIdException::forInvalidId($value); - } -} diff --git a/src/Authentication/Application/Query/Session/FindSessionByIdInterface.php b/src/Context/Authentication/Application/Query/Session/FindSessionByIdInterface.php similarity index 83% rename from src/Authentication/Application/Query/Session/FindSessionByIdInterface.php rename to src/Context/Authentication/Application/Query/Session/FindSessionByIdInterface.php index 8617ee6..cd251cf 100644 --- a/src/Authentication/Application/Query/Session/FindSessionByIdInterface.php +++ b/src/Context/Authentication/Application/Query/Session/FindSessionByIdInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Application\Query\Session; +namespace Webify\User\Context\Authentication\Application\Query\Session; -use Webify\User\Authentication\Domain\ValueObject\SessionId; +use Webify\User\Context\Authentication\Domain\ValueObject\SessionId; /** * Query class defines the contract for a query to find a session by its identifier. diff --git a/src/Authentication/Application/Query/Session/FindSessionsByUserInterface.php b/src/Context/Authentication/Application/Query/Session/FindSessionsByUserInterface.php similarity index 89% rename from src/Authentication/Application/Query/Session/FindSessionsByUserInterface.php rename to src/Context/Authentication/Application/Query/Session/FindSessionsByUserInterface.php index d94ef09..b5e6b2b 100644 --- a/src/Authentication/Application/Query/Session/FindSessionsByUserInterface.php +++ b/src/Context/Authentication/Application/Query/Session/FindSessionsByUserInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Application\Query\Session; +namespace Webify\User\Context\Authentication\Application\Query\Session; -use Webify\User\Authentication\Domain\ValueObject\ChallengeSecretInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\ChallengeSecretInterface; /** * Query class defines the contract for a query to find sessions by user. diff --git a/src/Authentication/Application/Query/Session/Session.php b/src/Context/Authentication/Application/Query/Session/Session.php similarity index 89% rename from src/Authentication/Application/Query/Session/Session.php rename to src/Context/Authentication/Application/Query/Session/Session.php index 02bcf87..5722998 100644 --- a/src/Authentication/Application/Query/Session/Session.php +++ b/src/Context/Authentication/Application/Query/Session/Session.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Application\Query\Session; +namespace Webify\User\Context\Authentication\Application\Query\Session; /** * Session read model. diff --git a/src/Authentication/Application/Query/Session/SessionCollection.php b/src/Context/Authentication/Application/Query/Session/SessionCollection.php similarity index 89% rename from src/Authentication/Application/Query/Session/SessionCollection.php rename to src/Context/Authentication/Application/Query/Session/SessionCollection.php index 60cf474..5a05bbe 100644 --- a/src/Authentication/Application/Query/Session/SessionCollection.php +++ b/src/Context/Authentication/Application/Query/Session/SessionCollection.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Application\Query\Session; +namespace Webify\User\Context\Authentication\Application\Query\Session; use Webify\Base\Contract\Collection\Collection; diff --git a/src/Authentication/Domain/Service/ChallengeBase.php b/src/Context/Authentication/Application/Service/ChallengeBase.php similarity index 72% rename from src/Authentication/Domain/Service/ChallengeBase.php rename to src/Context/Authentication/Application/Service/ChallengeBase.php index e3986f8..f0647b5 100644 --- a/src/Authentication/Domain/Service/ChallengeBase.php +++ b/src/Context/Authentication/Application/Service/ChallengeBase.php @@ -11,34 +11,32 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Service; +namespace Webify\User\Context\Authentication\Application\Service; -use DateTimeImmutable; -use DateTimeZone; use Webify\Base\Domain\Contract\Authentication\{ AuthenticatedUser, CredentialsInterface, StrategyInterface, UserCredentials, - UserCredentialsLookupInterface + UserCredentialsLookupInterface, }; use Webify\Base\Domain\Contract\Authentication\Service\{ChallengeBasedInterface, StrategyRegisterInterface}; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Entity\Session; -use Webify\User\Authentication\Domain\Exception\{ +use Webify\User\Context\Authentication\Domain\Entity\Session; +use Webify\User\Context\Authentication\Domain\Exception\{ AuthenticationFailedException, ChallengeNotFoundException, - InvalidChallengeSecretException + InvalidChallengeSecretException, }; -use Webify\User\Authentication\Domain\Guard\UserMustBeActive; -use Webify\User\Authentication\Domain\ValueObject\{ +use Webify\User\Context\Authentication\Domain\Guard\UserMustBeActive; +use Webify\User\Context\Authentication\Domain\ValueObject\{ AuthenticatedUser as AuthenticatedUserValueObject, ChallengeCode, ChallengeSecretInterface, ChallengeToken, ChallengeType, - UserId }; +use Webify\User\Domain\ValueObject\{UserId, UserStatus}; /** * Implementation of the challenge-based authentication service. @@ -57,7 +55,6 @@ public function __construct( private UserCredentialsLookupInterface $userLookup, private StrategyRegisterInterface $strategyRegister, private UserMustBeActive $userMustBeActive, - private UserStatusTranslator $userStatusTranslator, private VerifyChallenge $verifyChallenge, private OpenSession $openSession ) {} @@ -71,7 +68,7 @@ public function initiate(CredentialsInterface $credentials): void { $user = $this->userLookup($credentials); - $this->userMustBeActive->guard($this->userStatusTranslator->translate($user->status)); + $this->userMustBeActive->guard(UserStatus::fromString($user->status)); $strategy = $this->strategyLookup($credentials); @@ -91,7 +88,7 @@ public function complete(CredentialsInterface $credentials): AuthenticatedUser $user = $this->userLookup($credentials); - $this->userMustBeActive->guard($this->userStatusTranslator->translate($user->status)); + $this->userMustBeActive->guard(UserStatus::fromString($user->status)); $userId = UserId::fromString($user->id); $secret = $this->identifySecretType($credentials); @@ -140,11 +137,13 @@ private function identifySecretType(CredentialsInterface $credentials): Challeng throw AuthenticationFailedException::forInvalid(); } + $secret = $this->requiredString($credentials, 'secret'); + if ($type->isCode()) { - return ChallengeCode::fromString($credentials->get('secret')); + return ChallengeCode::fromString($secret); } - return ChallengeToken::fromString($credentials->get('secret')); + return ChallengeToken::fromString($secret); } /** @@ -156,7 +155,7 @@ private function userLookup(CredentialsInterface $credentials): UserCredentials throw AuthenticationFailedException::forMissingEmail(); } - $email = $credentials->get('email'); + $email = $this->requiredString($credentials, 'email'); $user = $this->userLookup->findByEmail($email); if (null === $user) { @@ -166,17 +165,39 @@ private function userLookup(CredentialsInterface $credentials): UserCredentials return $user; } + /** + * Reads a credential that must be present and must be a string. + * + * `KeyValueReaderInterface::get()` returns `mixed`, so a present key can still hold a + * non-string value. Narrowing here keeps the rest of the flow type-safe and turns a + * malformed payload into an authentication failure rather than a `TypeError`. + * + * @throws AuthenticationFailedException if the value is missing or not a string + */ + private function requiredString(CredentialsInterface $credentials, string $key): string + { + $value = $credentials->get($key); + + if (!is_string($value)) { + throw AuthenticationFailedException::forInvalid(); + } + + return $value; + } + /** * Opens a session for the user. */ private function openSession(UserId $userId): Session { + $datetime = DateTime::fromString( + sprintf('+%d minutes', self::SESSION_TTL_MINUTES), + 'UTC' + ); + return $this->openSession->open( AuthenticatedUserValueObject::fromSuccessfulAuthentication($userId), - new DateTimeImmutable( - sprintf('+%d minutes', self::SESSION_TTL_MINUTES), - new DateTimeZone('UTC') - ) + $datetime->toNative() ); } } diff --git a/src/Authentication/Domain/Service/IssueChallenge.php b/src/Context/Authentication/Application/Service/IssueChallenge.php similarity index 89% rename from src/Authentication/Domain/Service/IssueChallenge.php rename to src/Context/Authentication/Application/Service/IssueChallenge.php index 69f41c4..0c0de65 100644 --- a/src/Authentication/Domain/Service/IssueChallenge.php +++ b/src/Context/Authentication/Application/Service/IssueChallenge.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Service; +namespace Webify\User\Context\Authentication\Application\Service; use DateInvalidTimeZoneException; use DateMalformedStringException; @@ -21,9 +21,10 @@ use Webify\Base\Domain\Exception\DateTimeException; use Webify\Base\Domain\Service\UlidGeneratorInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Entity\Challenge; -use Webify\User\Authentication\Domain\Repository\ChallengeRepositoryInterface; -use Webify\User\Authentication\Domain\ValueObject\{ChallengeId, ChallengeType, UserId}; +use Webify\User\Context\Authentication\Domain\Entity\Challenge; +use Webify\User\Context\Authentication\Domain\Repository\ChallengeRepositoryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\{ChallengeId, ChallengeType}; +use Webify\User\Domain\ValueObject\UserId; /** * IssueChallenge creates and persists a new challenge, triggers delivery, diff --git a/src/Authentication/Domain/Service/OpenSession.php b/src/Context/Authentication/Application/Service/OpenSession.php similarity index 84% rename from src/Authentication/Domain/Service/OpenSession.php rename to src/Context/Authentication/Application/Service/OpenSession.php index 984d4a4..f971ba0 100644 --- a/src/Authentication/Domain/Service/OpenSession.php +++ b/src/Context/Authentication/Application/Service/OpenSession.php @@ -11,15 +11,15 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Service; +namespace Webify\User\Context\Authentication\Application\Service; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Entity\Session; -use Webify\User\Authentication\Domain\Repository\SessionRepositoryInterface; -use Webify\User\Authentication\Domain\ValueObject\{AccessToken, AuthenticatedUser, RefreshToken, SessionId}; +use Webify\User\Context\Authentication\Domain\Entity\Session; +use Webify\User\Context\Authentication\Domain\Repository\SessionRepositoryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\{AccessToken, AuthenticatedUser, RefreshToken, SessionId}; /** * OpenSession domain service handles the opening of a new session. diff --git a/src/Authentication/Domain/Service/PasswordBase.php b/src/Context/Authentication/Application/Service/PasswordBase.php similarity index 64% rename from src/Authentication/Domain/Service/PasswordBase.php rename to src/Context/Authentication/Application/Service/PasswordBase.php index 58cb171..a40ad8c 100644 --- a/src/Authentication/Domain/Service/PasswordBase.php +++ b/src/Context/Authentication/Application/Service/PasswordBase.php @@ -11,28 +11,20 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Service; +namespace Webify\User\Context\Authentication\Application\Service; use DateTimeImmutable; use DateTimeZone; -use Webify\Base\Domain\Contract\Authentication\{ - AuthenticatedUser, - CredentialsInterface, - Service\PasswordBaseInterface, - UserCredentials, - UserCredentialsLookupInterface -}; +use Webify\Base\Domain\Contract\Authentication\{AuthenticatedUser, CredentialsInterface, UserCredentials, UserCredentialsLookupInterface}; +use Webify\Base\Domain\Contract\Authentication\Service\PasswordBaseInterface; use Webify\Base\Domain\Contract\Identity\Service\PasswordHasherInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Entity\Session; -use Webify\User\Authentication\Domain\Exception\AuthenticationFailedException; -use Webify\User\Authentication\Domain\Guard\UserMustBeActive; -use Webify\User\Authentication\Domain\ValueObject\{ - AuthenticatedUser as AuthenticatedUserValueObject, - ChallengeCode, - ChallengeType, - UserId -}; +use Webify\User\Context\Authentication\Domain\Entity\Session; +use Webify\User\Context\Authentication\Domain\Exception\AuthenticationFailedException; +use Webify\User\Context\Authentication\Domain\Guard\UserMustBeActive; +use Webify\User\Context\Authentication\Domain\Service\ChallengeSecretDeliveryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\{AuthenticatedUser as AuthenticatedUserValueObject, ChallengeCode, ChallengeType}; +use Webify\User\Domain\ValueObject\{UserId, UserStatus}; /** * The implementation of the password base authentication service. @@ -51,7 +43,6 @@ public function __construct( private UserCredentialsLookupInterface $credentialLookup, private PasswordHasherInterface $passwordHasher, private UserMustBeActive $userMustBeActive, - private UserStatusTranslator $userStatusTranslator, private IssueChallenge $issueChallenge, private OpenSession $openSession, private ChallengeSecretDeliveryInterface $delivery @@ -72,11 +63,14 @@ public function authenticate(CredentialsInterface $request): ?AuthenticatedUser throw AuthenticationFailedException::forMissingPassword(); } - $userCredentials = $this->userLookup($request->get('email')); + $email = $this->requiredString($request, 'email'); + $password = $this->requiredString($request, 'password'); - $this->userMustBeActive->guard($this->userStatusTranslator->translate($userCredentials->status)); + $userCredentials = $this->userLookup($email); - if (!$this->passwordHasher->verify($request->get('password'), $userCredentials->passwordHash)) { + $this->userMustBeActive->guard(UserStatus::fromString($userCredentials->status)); + + if (!$this->passwordHasher->verify($password, $userCredentials->passwordHash)) { throw AuthenticationFailedException::forInvalid(); } @@ -118,6 +112,26 @@ private function userLookup(string $email): UserCredentials return $userCredentials; } + /** + * Reads a credential that must be present and must be a string. + * + * `KeyValueReaderInterface::get()` returns `mixed`, so a present key can still hold a + * non-string value. Narrowing here keeps the rest of the flow type-safe and turns a + * malformed payload into an authentication failure rather than a `TypeError`. + * + * @throws AuthenticationFailedException if the value is missing or not a string + */ + private function requiredString(CredentialsInterface $credentials, string $key): string + { + $value = $credentials->get($key); + + if (!is_string($value)) { + throw AuthenticationFailedException::forInvalid(); + } + + return $value; + } + /** * Issues a challenge code for the user when the user enabled two-factor authentication. */ diff --git a/src/Authentication/Domain/Service/RefreshSession.php b/src/Context/Authentication/Application/Service/RefreshSession.php similarity index 88% rename from src/Authentication/Domain/Service/RefreshSession.php rename to src/Context/Authentication/Application/Service/RefreshSession.php index 0a71116..3687c6d 100644 --- a/src/Authentication/Domain/Service/RefreshSession.php +++ b/src/Context/Authentication/Application/Service/RefreshSession.php @@ -11,13 +11,13 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Service; +namespace Webify\User\Context\Authentication\Application\Service; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Repository\SessionRepositoryInterface; -use Webify\User\Authentication\Domain\ValueObject\{AccessToken, RefreshToken}; +use Webify\User\Context\Authentication\Domain\Repository\SessionRepositoryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\{AccessToken, RefreshToken}; /** * RefreshSession domain service handles the refreshing of the session. diff --git a/src/Authentication/Domain/Service/RevokeSession.php b/src/Context/Authentication/Application/Service/RevokeSession.php similarity index 85% rename from src/Authentication/Domain/Service/RevokeSession.php rename to src/Context/Authentication/Application/Service/RevokeSession.php index 8d4a256..02f51c4 100644 --- a/src/Authentication/Domain/Service/RevokeSession.php +++ b/src/Context/Authentication/Application/Service/RevokeSession.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Service; +namespace Webify\User\Context\Authentication\Application\Service; use Webify\Base\Domain\Event\DomainEventPublisherInterface; -use Webify\User\Authentication\Domain\Repository\SessionRepositoryInterface; -use Webify\User\Authentication\Domain\ValueObject\SessionId; +use Webify\User\Context\Authentication\Domain\Repository\SessionRepositoryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\SessionId; /** * RevokeSession domain service handles the revoking of the session. diff --git a/src/Authentication/Domain/Service/VerifyChallenge.php b/src/Context/Authentication/Application/Service/VerifyChallenge.php similarity index 79% rename from src/Authentication/Domain/Service/VerifyChallenge.php rename to src/Context/Authentication/Application/Service/VerifyChallenge.php index 11d1c72..f559755 100644 --- a/src/Authentication/Domain/Service/VerifyChallenge.php +++ b/src/Context/Authentication/Application/Service/VerifyChallenge.php @@ -11,16 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Service; +namespace Webify\User\Context\Authentication\Application\Service; use Webify\Base\Domain\Event\DomainEventPublisherInterface; -use Webify\User\Authentication\Domain\Entity\Challenge; -use Webify\User\Authentication\Domain\Exception\InvalidChallengeSecretException; -use Webify\User\Authentication\Domain\Repository\ChallengeRepositoryInterface; -use Webify\User\Authentication\Domain\ValueObject\{ - ChallengeSecretInterface, - UserId -}; +use Webify\User\Context\Authentication\Domain\Entity\Challenge; +use Webify\User\Context\Authentication\Domain\Exception\InvalidChallengeSecretException; +use Webify\User\Context\Authentication\Domain\Repository\ChallengeRepositoryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\ChallengeSecretInterface; +use Webify\User\Domain\ValueObject\UserId; /** * VerifyChallenge domain service verifies the challenge secret and updates the challenge state accordingly. diff --git a/src/Authentication/Domain/Strategy/ChallengeCodeStrategy.php b/src/Context/Authentication/Application/Strategy/ChallengeCodeStrategy.php similarity index 81% rename from src/Authentication/Domain/Strategy/ChallengeCodeStrategy.php rename to src/Context/Authentication/Application/Strategy/ChallengeCodeStrategy.php index 22f740b..da3fb66 100644 --- a/src/Authentication/Domain/Strategy/ChallengeCodeStrategy.php +++ b/src/Context/Authentication/Application/Strategy/ChallengeCodeStrategy.php @@ -11,11 +11,13 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Strategy; +namespace Webify\User\Context\Authentication\Application\Strategy; use Webify\Base\Domain\Contract\Authentication\{CredentialsInterface, StrategyInterface, UserCredentials}; -use Webify\User\Authentication\Domain\Service\{ChallengeSecretDeliveryInterface, IssueChallenge}; -use Webify\User\Authentication\Domain\ValueObject\{ChallengeCode, ChallengeType, UserId}; +use Webify\User\Context\Authentication\Application\Service\IssueChallenge; +use Webify\User\Context\Authentication\Domain\Service\ChallengeSecretDeliveryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\{ChallengeCode, ChallengeType}; +use Webify\User\Domain\ValueObject\UserId; /** * ChallengeCodeStrategy handles challenge code authentication flow that sent via email or any other channels. diff --git a/src/Authentication/Domain/Strategy/ChallengeTokenStrategy.php b/src/Context/Authentication/Application/Strategy/ChallengeTokenStrategy.php similarity index 81% rename from src/Authentication/Domain/Strategy/ChallengeTokenStrategy.php rename to src/Context/Authentication/Application/Strategy/ChallengeTokenStrategy.php index 10ef5f4..34ec609 100644 --- a/src/Authentication/Domain/Strategy/ChallengeTokenStrategy.php +++ b/src/Context/Authentication/Application/Strategy/ChallengeTokenStrategy.php @@ -11,11 +11,13 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Strategy; +namespace Webify\User\Context\Authentication\Application\Strategy; use Webify\Base\Domain\Contract\Authentication\{CredentialsInterface, StrategyInterface, UserCredentials}; -use Webify\User\Authentication\Domain\Service\{ChallengeSecretDeliveryInterface, IssueChallenge}; -use Webify\User\Authentication\Domain\ValueObject\{ChallengeToken, ChallengeType, UserId}; +use Webify\User\Context\Authentication\Application\Service\IssueChallenge; +use Webify\User\Context\Authentication\Domain\Service\ChallengeSecretDeliveryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\{ChallengeToken, ChallengeType}; +use Webify\User\Domain\ValueObject\UserId; /** * ChallengeTokenStrategy handles challenge token authentication flow (via a magic link) that sent by email. diff --git a/src/Authentication/Domain/Entity/Challenge.php b/src/Context/Authentication/Domain/Entity/Challenge.php similarity index 90% rename from src/Authentication/Domain/Entity/Challenge.php rename to src/Context/Authentication/Domain/Entity/Challenge.php index fcaa6cb..0df777f 100644 --- a/src/Authentication/Domain/Entity/Challenge.php +++ b/src/Context/Authentication/Domain/Entity/Challenge.php @@ -11,21 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Entity; +namespace Webify\User\Context\Authentication\Domain\Entity; use Webify\Base\Domain\Entity\AggregateRoot; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Event\{ChallengeFailed, ChallengeVerified}; -use Webify\User\Authentication\Domain\Exception\{ChallengeVerificationFailedException, InvalidChallengeSecretException}; -use Webify\User\Authentication\Domain\ValueObject\{ - ChallengeCode, - ChallengeId, - ChallengeSecretInterface, - ChallengeStatus, - ChallengeToken, - ChallengeType, - UserId -}; +use Webify\User\Context\Authentication\Domain\Event\{ChallengeFailed, ChallengeVerified}; +use Webify\User\Context\Authentication\Domain\Exception\{ChallengeVerificationFailedException, InvalidChallengeSecretException}; +use Webify\User\Context\Authentication\Domain\ValueObject\{ChallengeCode, ChallengeId, ChallengeSecretInterface, ChallengeStatus, ChallengeToken, ChallengeType}; +use Webify\User\Domain\ValueObject\UserId; /** * Challenge aggregate root. diff --git a/src/Authentication/Domain/Entity/Session.php b/src/Context/Authentication/Domain/Entity/Session.php similarity index 92% rename from src/Authentication/Domain/Entity/Session.php rename to src/Context/Authentication/Domain/Entity/Session.php index 233c8c9..37a991d 100644 --- a/src/Authentication/Domain/Entity/Session.php +++ b/src/Context/Authentication/Domain/Entity/Session.php @@ -11,18 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Entity; +namespace Webify\User\Context\Authentication\Domain\Entity; use Webify\Base\Domain\Entity\AggregateRoot; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Event\{SessionWasOpened, SessionWasRefreshed, SessionWasRevoked}; -use Webify\User\Authentication\Domain\Exception\CannotRefreshSessionException; -use Webify\User\Authentication\Domain\ValueObject\{ - AccessToken, - RefreshToken, - SessionId, - UserId -}; +use Webify\User\Context\Authentication\Domain\Event\{SessionWasOpened, SessionWasRefreshed, SessionWasRevoked}; +use Webify\User\Context\Authentication\Domain\Exception\CannotRefreshSessionException; +use Webify\User\Context\Authentication\Domain\ValueObject\{AccessToken, RefreshToken, SessionId}; +use Webify\User\Domain\ValueObject\UserId; /** * Session aggregate root. diff --git a/src/Authentication/Domain/Event/ChallengeFailed.php b/src/Context/Authentication/Domain/Event/ChallengeFailed.php similarity index 94% rename from src/Authentication/Domain/Event/ChallengeFailed.php rename to src/Context/Authentication/Domain/Event/ChallengeFailed.php index 361f65f..1c8d0d9 100644 --- a/src/Authentication/Domain/Event/ChallengeFailed.php +++ b/src/Context/Authentication/Domain/Event/ChallengeFailed.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Event; +namespace Webify\User\Context\Authentication\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Authentication/Domain/Event/ChallengeVerified.php b/src/Context/Authentication/Domain/Event/ChallengeVerified.php similarity index 94% rename from src/Authentication/Domain/Event/ChallengeVerified.php rename to src/Context/Authentication/Domain/Event/ChallengeVerified.php index 7f0db81..d34ff0e 100644 --- a/src/Authentication/Domain/Event/ChallengeVerified.php +++ b/src/Context/Authentication/Domain/Event/ChallengeVerified.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Event; +namespace Webify\User\Context\Authentication\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Authentication/Domain/Event/SessionWasOpened.php b/src/Context/Authentication/Domain/Event/SessionWasOpened.php similarity index 94% rename from src/Authentication/Domain/Event/SessionWasOpened.php rename to src/Context/Authentication/Domain/Event/SessionWasOpened.php index 5587f76..a31b8ad 100644 --- a/src/Authentication/Domain/Event/SessionWasOpened.php +++ b/src/Context/Authentication/Domain/Event/SessionWasOpened.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Event; +namespace Webify\User\Context\Authentication\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Authentication/Domain/Event/SessionWasRefreshed.php b/src/Context/Authentication/Domain/Event/SessionWasRefreshed.php similarity index 94% rename from src/Authentication/Domain/Event/SessionWasRefreshed.php rename to src/Context/Authentication/Domain/Event/SessionWasRefreshed.php index 2f2fc79..5f23482 100644 --- a/src/Authentication/Domain/Event/SessionWasRefreshed.php +++ b/src/Context/Authentication/Domain/Event/SessionWasRefreshed.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Event; +namespace Webify\User\Context\Authentication\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Authentication/Domain/Event/SessionWasRevoked.php b/src/Context/Authentication/Domain/Event/SessionWasRevoked.php similarity index 94% rename from src/Authentication/Domain/Event/SessionWasRevoked.php rename to src/Context/Authentication/Domain/Event/SessionWasRevoked.php index 91bd071..d5ae10e 100644 --- a/src/Authentication/Domain/Event/SessionWasRevoked.php +++ b/src/Context/Authentication/Domain/Event/SessionWasRevoked.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Event; +namespace Webify\User\Context\Authentication\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Authentication/Domain/Exception/AccessTokenGenerationFailedException.php b/src/Context/Authentication/Domain/Exception/AccessTokenGenerationFailedException.php similarity index 96% rename from src/Authentication/Domain/Exception/AccessTokenGenerationFailedException.php rename to src/Context/Authentication/Domain/Exception/AccessTokenGenerationFailedException.php index baed523..ed3d160 100644 --- a/src/Authentication/Domain/Exception/AccessTokenGenerationFailedException.php +++ b/src/Context/Authentication/Domain/Exception/AccessTokenGenerationFailedException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use RuntimeException; use Throwable; diff --git a/src/Authentication/Domain/Exception/AuthenticationFailedException.php b/src/Context/Authentication/Domain/Exception/AuthenticationFailedException.php similarity index 98% rename from src/Authentication/Domain/Exception/AuthenticationFailedException.php rename to src/Context/Authentication/Domain/Exception/AuthenticationFailedException.php index 7dc5ee8..58af039 100644 --- a/src/Authentication/Domain/Exception/AuthenticationFailedException.php +++ b/src/Context/Authentication/Domain/Exception/AuthenticationFailedException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/CannotRefreshSessionException.php b/src/Context/Authentication/Domain/Exception/CannotRefreshSessionException.php similarity index 95% rename from src/Authentication/Domain/Exception/CannotRefreshSessionException.php rename to src/Context/Authentication/Domain/Exception/CannotRefreshSessionException.php index 5ff78d8..8689793 100644 --- a/src/Authentication/Domain/Exception/CannotRefreshSessionException.php +++ b/src/Context/Authentication/Domain/Exception/CannotRefreshSessionException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use DomainException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/ChallengeCodeGenerationFailedException.php b/src/Context/Authentication/Domain/Exception/ChallengeCodeGenerationFailedException.php similarity index 96% rename from src/Authentication/Domain/Exception/ChallengeCodeGenerationFailedException.php rename to src/Context/Authentication/Domain/Exception/ChallengeCodeGenerationFailedException.php index 1fabf19..e129bb8 100644 --- a/src/Authentication/Domain/Exception/ChallengeCodeGenerationFailedException.php +++ b/src/Context/Authentication/Domain/Exception/ChallengeCodeGenerationFailedException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use RuntimeException; use Throwable; diff --git a/src/Authentication/Domain/Exception/ChallengeNotFoundException.php b/src/Context/Authentication/Domain/Exception/ChallengeNotFoundException.php similarity index 96% rename from src/Authentication/Domain/Exception/ChallengeNotFoundException.php rename to src/Context/Authentication/Domain/Exception/ChallengeNotFoundException.php index 49f1704..efb3a35 100644 --- a/src/Authentication/Domain/Exception/ChallengeNotFoundException.php +++ b/src/Context/Authentication/Domain/Exception/ChallengeNotFoundException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use RuntimeException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/ChallengeTokenGenerationFailedException.php b/src/Context/Authentication/Domain/Exception/ChallengeTokenGenerationFailedException.php similarity index 96% rename from src/Authentication/Domain/Exception/ChallengeTokenGenerationFailedException.php rename to src/Context/Authentication/Domain/Exception/ChallengeTokenGenerationFailedException.php index 299e99c..fdf08b4 100644 --- a/src/Authentication/Domain/Exception/ChallengeTokenGenerationFailedException.php +++ b/src/Context/Authentication/Domain/Exception/ChallengeTokenGenerationFailedException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use RuntimeException; use Throwable; diff --git a/src/Authentication/Domain/Exception/ChallengeVerificationFailedException.php b/src/Context/Authentication/Domain/Exception/ChallengeVerificationFailedException.php similarity index 97% rename from src/Authentication/Domain/Exception/ChallengeVerificationFailedException.php rename to src/Context/Authentication/Domain/Exception/ChallengeVerificationFailedException.php index 10dc185..715b6b6 100644 --- a/src/Authentication/Domain/Exception/ChallengeVerificationFailedException.php +++ b/src/Context/Authentication/Domain/Exception/ChallengeVerificationFailedException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use DomainException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/InvalidAccessTokenException.php b/src/Context/Authentication/Domain/Exception/InvalidAccessTokenException.php similarity index 95% rename from src/Authentication/Domain/Exception/InvalidAccessTokenException.php rename to src/Context/Authentication/Domain/Exception/InvalidAccessTokenException.php index 6260fc8..8ff4291 100644 --- a/src/Authentication/Domain/Exception/InvalidAccessTokenException.php +++ b/src/Context/Authentication/Domain/Exception/InvalidAccessTokenException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/InvalidChallengeCodeException.php b/src/Context/Authentication/Domain/Exception/InvalidChallengeCodeException.php similarity index 95% rename from src/Authentication/Domain/Exception/InvalidChallengeCodeException.php rename to src/Context/Authentication/Domain/Exception/InvalidChallengeCodeException.php index 13a5eb6..db010cc 100644 --- a/src/Authentication/Domain/Exception/InvalidChallengeCodeException.php +++ b/src/Context/Authentication/Domain/Exception/InvalidChallengeCodeException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/InvalidChallengeIdException.php b/src/Context/Authentication/Domain/Exception/InvalidChallengeIdException.php similarity index 95% rename from src/Authentication/Domain/Exception/InvalidChallengeIdException.php rename to src/Context/Authentication/Domain/Exception/InvalidChallengeIdException.php index 0898aed..f24b417 100644 --- a/src/Authentication/Domain/Exception/InvalidChallengeIdException.php +++ b/src/Context/Authentication/Domain/Exception/InvalidChallengeIdException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/InvalidChallengeSecretException.php b/src/Context/Authentication/Domain/Exception/InvalidChallengeSecretException.php similarity index 95% rename from src/Authentication/Domain/Exception/InvalidChallengeSecretException.php rename to src/Context/Authentication/Domain/Exception/InvalidChallengeSecretException.php index 2e403c8..a58255a 100644 --- a/src/Authentication/Domain/Exception/InvalidChallengeSecretException.php +++ b/src/Context/Authentication/Domain/Exception/InvalidChallengeSecretException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use DomainException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/InvalidChallengeTokenException.php b/src/Context/Authentication/Domain/Exception/InvalidChallengeTokenException.php similarity index 95% rename from src/Authentication/Domain/Exception/InvalidChallengeTokenException.php rename to src/Context/Authentication/Domain/Exception/InvalidChallengeTokenException.php index 32eff8c..4df6636 100644 --- a/src/Authentication/Domain/Exception/InvalidChallengeTokenException.php +++ b/src/Context/Authentication/Domain/Exception/InvalidChallengeTokenException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/InvalidChallengeTypeException.php b/src/Context/Authentication/Domain/Exception/InvalidChallengeTypeException.php similarity index 95% rename from src/Authentication/Domain/Exception/InvalidChallengeTypeException.php rename to src/Context/Authentication/Domain/Exception/InvalidChallengeTypeException.php index 5c66f32..8335f9e 100644 --- a/src/Authentication/Domain/Exception/InvalidChallengeTypeException.php +++ b/src/Context/Authentication/Domain/Exception/InvalidChallengeTypeException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/InvalidRefreshTokenException.php b/src/Context/Authentication/Domain/Exception/InvalidRefreshTokenException.php similarity index 95% rename from src/Authentication/Domain/Exception/InvalidRefreshTokenException.php rename to src/Context/Authentication/Domain/Exception/InvalidRefreshTokenException.php index 665462b..187b78a 100644 --- a/src/Authentication/Domain/Exception/InvalidRefreshTokenException.php +++ b/src/Context/Authentication/Domain/Exception/InvalidRefreshTokenException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/InvalidSessionIdException.php b/src/Context/Authentication/Domain/Exception/InvalidSessionIdException.php similarity index 95% rename from src/Authentication/Domain/Exception/InvalidSessionIdException.php rename to src/Context/Authentication/Domain/Exception/InvalidSessionIdException.php index 7925a8d..813f658 100644 --- a/src/Authentication/Domain/Exception/InvalidSessionIdException.php +++ b/src/Context/Authentication/Domain/Exception/InvalidSessionIdException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/InvalidUserCredentialException.php b/src/Context/Authentication/Domain/Exception/InvalidUserCredentialException.php similarity index 95% rename from src/Authentication/Domain/Exception/InvalidUserCredentialException.php rename to src/Context/Authentication/Domain/Exception/InvalidUserCredentialException.php index d01df68..25747e8 100644 --- a/src/Authentication/Domain/Exception/InvalidUserCredentialException.php +++ b/src/Context/Authentication/Domain/Exception/InvalidUserCredentialException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Exception/RefreshTokenGenerationFailedException.php b/src/Context/Authentication/Domain/Exception/RefreshTokenGenerationFailedException.php similarity index 96% rename from src/Authentication/Domain/Exception/RefreshTokenGenerationFailedException.php rename to src/Context/Authentication/Domain/Exception/RefreshTokenGenerationFailedException.php index 00f0d4a..0d1052f 100644 --- a/src/Authentication/Domain/Exception/RefreshTokenGenerationFailedException.php +++ b/src/Context/Authentication/Domain/Exception/RefreshTokenGenerationFailedException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use RuntimeException; use Throwable; diff --git a/src/Authentication/Domain/Exception/SessionNotFoundException.php b/src/Context/Authentication/Domain/Exception/SessionNotFoundException.php similarity index 97% rename from src/Authentication/Domain/Exception/SessionNotFoundException.php rename to src/Context/Authentication/Domain/Exception/SessionNotFoundException.php index 4e6ae2f..8e1b321 100644 --- a/src/Authentication/Domain/Exception/SessionNotFoundException.php +++ b/src/Context/Authentication/Domain/Exception/SessionNotFoundException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Exception; +namespace Webify\User\Context\Authentication\Domain\Exception; use RuntimeException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Domain/Guard/UserMustBeActive.php b/src/Context/Authentication/Domain/Guard/UserMustBeActive.php similarity index 78% rename from src/Authentication/Domain/Guard/UserMustBeActive.php rename to src/Context/Authentication/Domain/Guard/UserMustBeActive.php index 95552e1..03d2dde 100644 --- a/src/Authentication/Domain/Guard/UserMustBeActive.php +++ b/src/Context/Authentication/Domain/Guard/UserMustBeActive.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Guard; +namespace Webify\User\Context\Authentication\Domain\Guard; -use Webify\User\Authentication\Domain\Exception\AuthenticationFailedException; -use Webify\User\Authentication\Domain\ValueObject\UserStatus; +use Webify\User\Context\Authentication\Domain\Exception\AuthenticationFailedException; +use Webify\User\Domain\ValueObject\UserStatus; /** * Guard that ensures that the user is active. diff --git a/src/Authentication/Domain/Repository/ChallengeRepositoryInterface.php b/src/Context/Authentication/Domain/Repository/ChallengeRepositoryInterface.php similarity index 80% rename from src/Authentication/Domain/Repository/ChallengeRepositoryInterface.php rename to src/Context/Authentication/Domain/Repository/ChallengeRepositoryInterface.php index b3c6945..f19ffe4 100644 --- a/src/Authentication/Domain/Repository/ChallengeRepositoryInterface.php +++ b/src/Context/Authentication/Domain/Repository/ChallengeRepositoryInterface.php @@ -11,11 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Repository; +namespace Webify\User\Context\Authentication\Domain\Repository; -use Webify\User\Authentication\Domain\Entity\Challenge; -use Webify\User\Authentication\Domain\Exception\ChallengeNotFoundException; -use Webify\User\Authentication\Domain\ValueObject\{ChallengeId, UserId}; +use Webify\User\Context\Authentication\Domain\Entity\Challenge; +use Webify\User\Context\Authentication\Domain\Exception\ChallengeNotFoundException; +use Webify\User\Context\Authentication\Domain\ValueObject\ChallengeId; +use Webify\User\Domain\ValueObject\UserId; /** * ChallengeRepositoryInterface defines the contract for an authentication challenge repository. diff --git a/src/Authentication/Domain/Repository/SessionRepositoryInterface.php b/src/Context/Authentication/Domain/Repository/SessionRepositoryInterface.php similarity index 81% rename from src/Authentication/Domain/Repository/SessionRepositoryInterface.php rename to src/Context/Authentication/Domain/Repository/SessionRepositoryInterface.php index 01bb4dc..b3cd20e 100644 --- a/src/Authentication/Domain/Repository/SessionRepositoryInterface.php +++ b/src/Context/Authentication/Domain/Repository/SessionRepositoryInterface.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Repository; +namespace Webify\User\Context\Authentication\Domain\Repository; -use Webify\User\Authentication\Domain\Entity\Session; -use Webify\User\Authentication\Domain\Exception\SessionNotFoundException; -use Webify\User\Authentication\Domain\ValueObject\{AccessToken, ChallengeSecretInterface, RefreshToken, SessionId}; +use Webify\User\Context\Authentication\Domain\Entity\Session; +use Webify\User\Context\Authentication\Domain\Exception\SessionNotFoundException; +use Webify\User\Context\Authentication\Domain\ValueObject\{AccessToken, ChallengeSecretInterface, RefreshToken, SessionId}; /** * SessionRepositoryInterface defines the contract for the session repository. diff --git a/src/Authentication/Domain/Service/ChallengeSecretDeliveryInterface.php b/src/Context/Authentication/Domain/Service/ChallengeSecretDeliveryInterface.php similarity index 88% rename from src/Authentication/Domain/Service/ChallengeSecretDeliveryInterface.php rename to src/Context/Authentication/Domain/Service/ChallengeSecretDeliveryInterface.php index 5c27987..d3f9f60 100644 --- a/src/Authentication/Domain/Service/ChallengeSecretDeliveryInterface.php +++ b/src/Context/Authentication/Domain/Service/ChallengeSecretDeliveryInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\Service; +namespace Webify\User\Context\Authentication\Domain\Service; -use Webify\User\Authentication\Domain\ValueObject\UserId; +use Webify\User\Domain\ValueObject\UserId; /** * The service defines the contract for delivering the authentication challenge secret. diff --git a/src/Authentication/Domain/ValueObject/AccessToken.php b/src/Context/Authentication/Domain/ValueObject/AccessToken.php similarity index 86% rename from src/Authentication/Domain/ValueObject/AccessToken.php rename to src/Context/Authentication/Domain/ValueObject/AccessToken.php index f258e59..873f35b 100644 --- a/src/Authentication/Domain/ValueObject/AccessToken.php +++ b/src/Context/Authentication/Domain/ValueObject/AccessToken.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authentication\Domain\ValueObject; use Webify\Base\Domain\Exception\SecureTokenGenerationFailedException; use Webify\Base\Domain\ValueObject\SecureToken; -use Webify\User\Authentication\Domain\Exception\{AccessTokenGenerationFailedException, InvalidAccessTokenException}; +use Webify\User\Context\Authentication\Domain\Exception\{AccessTokenGenerationFailedException, InvalidAccessTokenException}; /** * Access token value object. diff --git a/src/Authentication/Domain/ValueObject/AuthenticatedUser.php b/src/Context/Authentication/Domain/ValueObject/AuthenticatedUser.php similarity index 93% rename from src/Authentication/Domain/ValueObject/AuthenticatedUser.php rename to src/Context/Authentication/Domain/ValueObject/AuthenticatedUser.php index 16c0c93..e1567d0 100644 --- a/src/Authentication/Domain/ValueObject/AuthenticatedUser.php +++ b/src/Context/Authentication/Domain/ValueObject/AuthenticatedUser.php @@ -11,9 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authentication\Domain\ValueObject; use Webify\Base\Domain\ValueObject\DateTime; +use Webify\User\Domain\ValueObject\UserId; /** * Authenticated user value object. diff --git a/src/Authentication/Domain/ValueObject/ChallengeCode.php b/src/Context/Authentication/Domain/ValueObject/ChallengeCode.php similarity index 92% rename from src/Authentication/Domain/ValueObject/ChallengeCode.php rename to src/Context/Authentication/Domain/ValueObject/ChallengeCode.php index 44853a2..f2e2144 100644 --- a/src/Authentication/Domain/ValueObject/ChallengeCode.php +++ b/src/Context/Authentication/Domain/ValueObject/ChallengeCode.php @@ -11,13 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authentication\Domain\ValueObject; use Random\RandomException; -use Webify\User\Authentication\Domain\Exception\{ - ChallengeCodeGenerationFailedException, - InvalidChallengeCodeException -}; +use Webify\User\Context\Authentication\Domain\Exception\{ChallengeCodeGenerationFailedException, InvalidChallengeCodeException}; /** * Challenge code value object. diff --git a/src/Authentication/Domain/ValueObject/ChallengeId.php b/src/Context/Authentication/Domain/ValueObject/ChallengeId.php similarity index 83% rename from src/Authentication/Domain/ValueObject/ChallengeId.php rename to src/Context/Authentication/Domain/ValueObject/ChallengeId.php index d6522fc..e280e74 100644 --- a/src/Authentication/Domain/ValueObject/ChallengeId.php +++ b/src/Context/Authentication/Domain/ValueObject/ChallengeId.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authentication\Domain\ValueObject; use Webify\Base\Domain\ValueObject\AggregateId; -use Webify\User\Authentication\Domain\Exception\InvalidChallengeIdException; +use Webify\User\Context\Authentication\Domain\Exception\InvalidChallengeIdException; /** * Challenge ID value object. diff --git a/src/Authentication/Domain/ValueObject/ChallengeSecretInterface.php b/src/Context/Authentication/Domain/ValueObject/ChallengeSecretInterface.php similarity index 89% rename from src/Authentication/Domain/ValueObject/ChallengeSecretInterface.php rename to src/Context/Authentication/Domain/ValueObject/ChallengeSecretInterface.php index ce512f4..d42a9fd 100644 --- a/src/Authentication/Domain/ValueObject/ChallengeSecretInterface.php +++ b/src/Context/Authentication/Domain/ValueObject/ChallengeSecretInterface.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authentication\Domain\ValueObject; /** * The challenge secret interface. diff --git a/src/Authentication/Domain/ValueObject/ChallengeStatus.php b/src/Context/Authentication/Domain/ValueObject/ChallengeStatus.php similarity index 91% rename from src/Authentication/Domain/ValueObject/ChallengeStatus.php rename to src/Context/Authentication/Domain/ValueObject/ChallengeStatus.php index 541fef6..d8c45cb 100644 --- a/src/Authentication/Domain/ValueObject/ChallengeStatus.php +++ b/src/Context/Authentication/Domain/ValueObject/ChallengeStatus.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authentication\Domain\ValueObject; /** * The authentication challenge status value object. diff --git a/src/Authentication/Domain/ValueObject/ChallengeToken.php b/src/Context/Authentication/Domain/ValueObject/ChallengeToken.php similarity index 87% rename from src/Authentication/Domain/ValueObject/ChallengeToken.php rename to src/Context/Authentication/Domain/ValueObject/ChallengeToken.php index cbab07a..d50829a 100644 --- a/src/Authentication/Domain/ValueObject/ChallengeToken.php +++ b/src/Context/Authentication/Domain/ValueObject/ChallengeToken.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authentication\Domain\ValueObject; use Webify\Base\Domain\Exception\SecureTokenGenerationFailedException; use Webify\Base\Domain\ValueObject\SecureToken; -use Webify\User\Authentication\Domain\Exception\{ChallengeTokenGenerationFailedException, InvalidChallengeTokenException}; +use Webify\User\Context\Authentication\Domain\Exception\{ChallengeTokenGenerationFailedException, InvalidChallengeTokenException}; /** * Challenge token value object. diff --git a/src/Authentication/Domain/ValueObject/ChallengeType.php b/src/Context/Authentication/Domain/ValueObject/ChallengeType.php similarity index 92% rename from src/Authentication/Domain/ValueObject/ChallengeType.php rename to src/Context/Authentication/Domain/ValueObject/ChallengeType.php index abfd294..25c4bbb 100644 --- a/src/Authentication/Domain/ValueObject/ChallengeType.php +++ b/src/Context/Authentication/Domain/ValueObject/ChallengeType.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authentication\Domain\ValueObject; /** * The challenge type value object. diff --git a/src/Authentication/Domain/ValueObject/RefreshToken.php b/src/Context/Authentication/Domain/ValueObject/RefreshToken.php similarity index 85% rename from src/Authentication/Domain/ValueObject/RefreshToken.php rename to src/Context/Authentication/Domain/ValueObject/RefreshToken.php index 4b1ed39..0e9342e 100644 --- a/src/Authentication/Domain/ValueObject/RefreshToken.php +++ b/src/Context/Authentication/Domain/ValueObject/RefreshToken.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authentication\Domain\ValueObject; use Webify\Base\Domain\Exception\SecureTokenGenerationFailedException; use Webify\Base\Domain\ValueObject\SecureToken; -use Webify\User\Authentication\Domain\Exception\{InvalidRefreshTokenException, RefreshTokenGenerationFailedException}; +use Webify\User\Context\Authentication\Domain\Exception\{InvalidRefreshTokenException, RefreshTokenGenerationFailedException}; /** * Refresh token value object. diff --git a/src/Authentication/Domain/ValueObject/SessionId.php b/src/Context/Authentication/Domain/ValueObject/SessionId.php similarity index 83% rename from src/Authentication/Domain/ValueObject/SessionId.php rename to src/Context/Authentication/Domain/ValueObject/SessionId.php index d4fe2cb..b606504 100644 --- a/src/Authentication/Domain/ValueObject/SessionId.php +++ b/src/Context/Authentication/Domain/ValueObject/SessionId.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authentication\Domain\ValueObject; use Webify\Base\Domain\ValueObject\AggregateId; -use Webify\User\Authentication\Domain\Exception\InvalidSessionIdException; +use Webify\User\Context\Authentication\Domain\Exception\InvalidSessionIdException; /** * Session ID value object. diff --git a/src/Context/Authentication/Infrastructure/Container/ServiceDefinitions.php b/src/Context/Authentication/Infrastructure/Container/ServiceDefinitions.php new file mode 100644 index 0000000..460bc2f --- /dev/null +++ b/src/Context/Authentication/Infrastructure/Container/ServiceDefinitions.php @@ -0,0 +1,36 @@ + + */ +declare(strict_types=1); + +namespace Webify\User\Context\Authentication\Infrastructure\Container; + +use Webify\Base\Domain\Contract\Authentication\Service\StrategyRegisterInterface; +use Webify\Base\Infrastructure\Contract\DefinitionsInterface; +use Webify\User\Context\Authentication\Infrastructure\Service\StrategyRegister; + +use function DI\create; + +/** + * Description. + */ +final readonly class ServiceDefinitions implements DefinitionsInterface +{ + /** + * {@inheritDoc} + */ + public static function getDefinitions(): array + { + return [ + StrategyRegisterInterface::class => create(StrategyRegister::class), + ]; + } +} diff --git a/src/Authentication/Infrastructure/Exception/StrategyNotFoundException.php b/src/Context/Authentication/Infrastructure/Exception/StrategyNotFoundException.php similarity index 95% rename from src/Authentication/Infrastructure/Exception/StrategyNotFoundException.php rename to src/Context/Authentication/Infrastructure/Exception/StrategyNotFoundException.php index 4da4311..4056a05 100644 --- a/src/Authentication/Infrastructure/Exception/StrategyNotFoundException.php +++ b/src/Context/Authentication/Infrastructure/Exception/StrategyNotFoundException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Infrastructure\Exception; +namespace Webify\User\Context\Authentication\Infrastructure\Exception; use RuntimeException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authentication/Infrastructure/Service/StrategyRegister.php b/src/Context/Authentication/Infrastructure/Service/StrategyRegister.php similarity index 88% rename from src/Authentication/Infrastructure/Service/StrategyRegister.php rename to src/Context/Authentication/Infrastructure/Service/StrategyRegister.php index 0ae9611..c93c637 100644 --- a/src/Authentication/Infrastructure/Service/StrategyRegister.php +++ b/src/Context/Authentication/Infrastructure/Service/StrategyRegister.php @@ -11,11 +11,13 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Infrastructure\Service; +namespace Webify\User\Context\Authentication\Infrastructure\Service; use Webify\Base\Domain\Contract\Authentication\Service\StrategyRegisterInterface; use Webify\Base\Domain\Contract\Authentication\StrategyInterface; -use Webify\User\Authentication\Infrastructure\Exception\StrategyNotFoundException; +use Webify\User\Context\Authentication\Infrastructure\Exception\StrategyNotFoundException; + +use function array_key_exists; /** * Implementation of the StrategyRegisterInterface. diff --git a/src/Authorization/Application/Query/Role/FindAllRolesInterface.php b/src/Context/Authorization/Application/Query/Role/FindAllRolesInterface.php similarity index 89% rename from src/Authorization/Application/Query/Role/FindAllRolesInterface.php rename to src/Context/Authorization/Application/Query/Role/FindAllRolesInterface.php index 7cb064b..152fa78 100644 --- a/src/Authorization/Application/Query/Role/FindAllRolesInterface.php +++ b/src/Context/Authorization/Application/Query/Role/FindAllRolesInterface.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\Role; +namespace Webify\User\Context\Authorization\Application\Query\Role; /** * Query class defines the contract for a query to find all roles. diff --git a/src/Authorization/Application/Query/Role/FindRoleByIdInterface.php b/src/Context/Authorization/Application/Query/Role/FindRoleByIdInterface.php similarity index 82% rename from src/Authorization/Application/Query/Role/FindRoleByIdInterface.php rename to src/Context/Authorization/Application/Query/Role/FindRoleByIdInterface.php index 8bf7e25..e5a8ba0 100644 --- a/src/Authorization/Application/Query/Role/FindRoleByIdInterface.php +++ b/src/Context/Authorization/Application/Query/Role/FindRoleByIdInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\Role; +namespace Webify\User\Context\Authorization\Application\Query\Role; -use Webify\User\Authorization\Domain\ValueObject\RoleId; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleId; /** * Query class defines the contract for a query to find a role by its identifier. diff --git a/src/Authorization/Application/Query/Role/FindRoleBySlugInterface.php b/src/Context/Authorization/Application/Query/Role/FindRoleBySlugInterface.php similarity index 82% rename from src/Authorization/Application/Query/Role/FindRoleBySlugInterface.php rename to src/Context/Authorization/Application/Query/Role/FindRoleBySlugInterface.php index 8de00c1..30e58b0 100644 --- a/src/Authorization/Application/Query/Role/FindRoleBySlugInterface.php +++ b/src/Context/Authorization/Application/Query/Role/FindRoleBySlugInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\Role; +namespace Webify\User\Context\Authorization\Application\Query\Role; -use Webify\User\Authorization\Domain\ValueObject\RoleSlug; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleSlug; /** * Query class defines the contract for a query to find a role by its slug. diff --git a/src/Authorization/Application/Query/Role/Role.php b/src/Context/Authorization/Application/Query/Role/Role.php similarity index 92% rename from src/Authorization/Application/Query/Role/Role.php rename to src/Context/Authorization/Application/Query/Role/Role.php index 2b6791b..fe5d51f 100644 --- a/src/Authorization/Application/Query/Role/Role.php +++ b/src/Context/Authorization/Application/Query/Role/Role.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\Role; +namespace Webify\User\Context\Authorization\Application\Query\Role; /** * The Role read model represents raw data of a role entity. diff --git a/src/Authorization/Application/Query/Role/RoleCollection.php b/src/Context/Authorization/Application/Query/Role/RoleCollection.php similarity index 89% rename from src/Authorization/Application/Query/Role/RoleCollection.php rename to src/Context/Authorization/Application/Query/Role/RoleCollection.php index f2e4329..5c21229 100644 --- a/src/Authorization/Application/Query/Role/RoleCollection.php +++ b/src/Context/Authorization/Application/Query/Role/RoleCollection.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\Role; +namespace Webify\User\Context\Authorization\Application\Query\Role; use Webify\Base\Contract\Collection\Collection; diff --git a/src/Authorization/Application/Query/RoleAssignment/FindAllRoleAssignmentsInterface.php b/src/Context/Authorization/Application/Query/RoleAssignment/FindAllRoleAssignmentsInterface.php similarity index 91% rename from src/Authorization/Application/Query/RoleAssignment/FindAllRoleAssignmentsInterface.php rename to src/Context/Authorization/Application/Query/RoleAssignment/FindAllRoleAssignmentsInterface.php index 0f86a05..9431900 100644 --- a/src/Authorization/Application/Query/RoleAssignment/FindAllRoleAssignmentsInterface.php +++ b/src/Context/Authorization/Application/Query/RoleAssignment/FindAllRoleAssignmentsInterface.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\RoleAssignment; +namespace Webify\User\Context\Authorization\Application\Query\RoleAssignment; /** * RoleAssignmentQueryInterface defines the contract for a role assignment query. diff --git a/src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentByIdInterface.php b/src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentByIdInterface.php similarity index 79% rename from src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentByIdInterface.php rename to src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentByIdInterface.php index d952676..3867501 100644 --- a/src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentByIdInterface.php +++ b/src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentByIdInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\RoleAssignment; +namespace Webify\User\Context\Authorization\Application\Query\RoleAssignment; -use Webify\User\Authorization\Domain\ValueObject\RoleAssignmentId; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleAssignmentId; /** * Query class defines the contract for a query to find role assignment by its identifier. diff --git a/src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentBySubjectInterface.php b/src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentBySubjectInterface.php similarity index 85% rename from src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentBySubjectInterface.php rename to src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentBySubjectInterface.php index a8ccb6a..ce2722b 100644 --- a/src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentBySubjectInterface.php +++ b/src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentBySubjectInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\RoleAssignment; +namespace Webify\User\Context\Authorization\Application\Query\RoleAssignment; -use Webify\User\Authorization\Domain\ValueObject\SubjectId; +use Webify\User\Context\Authorization\Domain\ValueObject\SubjectId; /** * Query class defines the contract for a query to find role assignments by subject. diff --git a/src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByRoleInterface.php b/src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByRoleInterface.php similarity index 84% rename from src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByRoleInterface.php rename to src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByRoleInterface.php index 872b4c4..3250313 100644 --- a/src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByRoleInterface.php +++ b/src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByRoleInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\RoleAssignment; +namespace Webify\User\Context\Authorization\Application\Query\RoleAssignment; -use Webify\User\Authorization\Domain\ValueObject\RoleId; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleId; /** * Query class defines the contract for a query to find role assignments by role. diff --git a/src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByTenantInterface.php b/src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByTenantInterface.php similarity index 84% rename from src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByTenantInterface.php rename to src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByTenantInterface.php index 47f4454..afe316a 100644 --- a/src/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByTenantInterface.php +++ b/src/Context/Authorization/Application/Query/RoleAssignment/FindRoleAssignmentsByTenantInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\RoleAssignment; +namespace Webify\User\Context\Authorization\Application\Query\RoleAssignment; -use Webify\User\Authorization\Domain\ValueObject\TenantId; +use Webify\User\Context\Authorization\Domain\ValueObject\TenantId; /** * Query class defines the contract for a query to find role assignments by tenant. diff --git a/src/Authorization/Application/Query/RoleAssignment/RoleAssignment.php b/src/Context/Authorization/Application/Query/RoleAssignment/RoleAssignment.php similarity index 89% rename from src/Authorization/Application/Query/RoleAssignment/RoleAssignment.php rename to src/Context/Authorization/Application/Query/RoleAssignment/RoleAssignment.php index e197e54..ae9c762 100644 --- a/src/Authorization/Application/Query/RoleAssignment/RoleAssignment.php +++ b/src/Context/Authorization/Application/Query/RoleAssignment/RoleAssignment.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\RoleAssignment; +namespace Webify\User\Context\Authorization\Application\Query\RoleAssignment; use DateTimeImmutable; diff --git a/src/Authorization/Application/Query/RoleAssignment/RoleAssignmentCollection.php b/src/Context/Authorization/Application/Query/RoleAssignment/RoleAssignmentCollection.php similarity index 88% rename from src/Authorization/Application/Query/RoleAssignment/RoleAssignmentCollection.php rename to src/Context/Authorization/Application/Query/RoleAssignment/RoleAssignmentCollection.php index cdc49b9..38449c7 100644 --- a/src/Authorization/Application/Query/RoleAssignment/RoleAssignmentCollection.php +++ b/src/Context/Authorization/Application/Query/RoleAssignment/RoleAssignmentCollection.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Application\Query\RoleAssignment; +namespace Webify\User\Context\Authorization\Application\Query\RoleAssignment; use Webify\Base\Contract\Collection\Collection; diff --git a/src/Authorization/Domain/Service/AssignRole.php b/src/Context/Authorization/Application/Service/AssignRole.php similarity index 86% rename from src/Authorization/Domain/Service/AssignRole.php rename to src/Context/Authorization/Application/Service/AssignRole.php index d70594d..2463ca7 100644 --- a/src/Authorization/Domain/Service/AssignRole.php +++ b/src/Context/Authorization/Application/Service/AssignRole.php @@ -11,16 +11,16 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Service; +namespace Webify\User\Context\Authorization\Application\Service; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authorization\Domain\Entity\{Role, RoleAssignment}; -use Webify\User\Authorization\Domain\Guard\DuplicateRoleAssignment; -use Webify\User\Authorization\Domain\Repository\{RoleAssignmentRepositoryInterface, RoleRepositoryInterface}; -use Webify\User\Authorization\Domain\ValueObject\{RoleAssignmentId, RoleSlug, SubjectId, TenantId}; +use Webify\User\Context\Authorization\Domain\Entity\{Role, RoleAssignment}; +use Webify\User\Context\Authorization\Domain\Guard\DuplicateRoleAssignment; +use Webify\User\Context\Authorization\Domain\Repository\{RoleAssignmentRepositoryInterface, RoleRepositoryInterface}; +use Webify\User\Context\Authorization\Domain\ValueObject\{RoleAssignmentId, RoleSlug, SubjectId, TenantId}; /** * AssignRole service handles the assigning roles to subjects. diff --git a/src/Authorization/Domain/Service/CheckAccess.php b/src/Context/Authorization/Application/Service/CheckAccess.php similarity index 89% rename from src/Authorization/Domain/Service/CheckAccess.php rename to src/Context/Authorization/Application/Service/CheckAccess.php index 0e23657..868294a 100644 --- a/src/Authorization/Domain/Service/CheckAccess.php +++ b/src/Context/Authorization/Application/Service/CheckAccess.php @@ -11,13 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Service; +namespace Webify\User\Context\Authorization\Application\Service; -use Webify\Base\Domain\Contract\Authorization\{ - AuthorizableResourceInterface, - AuthorizableSubjectInterface, -}; +use Webify\Base\Domain\Contract\Authorization\{AuthorizableResourceInterface, AuthorizableSubjectInterface}; use Webify\Base\Domain\Exception\AccessDeniedException; +use Webify\User\Context\Authorization\Domain\Service\Authorization; /** * CheckAccess is the implementation of the `CheckAccessInterface` that uses the diff --git a/src/Authorization/Domain/Service/CreateRole.php b/src/Context/Authorization/Application/Service/CreateRole.php similarity index 86% rename from src/Authorization/Domain/Service/CreateRole.php rename to src/Context/Authorization/Application/Service/CreateRole.php index d131e04..d37520c 100644 --- a/src/Authorization/Domain/Service/CreateRole.php +++ b/src/Context/Authorization/Application/Service/CreateRole.php @@ -11,15 +11,15 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Service; +namespace Webify\User\Context\Authorization\Application\Service; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\{SlugifyInterface, UlidGeneratorInterface}; -use Webify\User\Authorization\Domain\Collection\PermissionCollection; -use Webify\User\Authorization\Domain\Entity\Role; -use Webify\User\Authorization\Domain\Guard\RoleAlreadyExists; -use Webify\User\Authorization\Domain\Repository\RoleRepositoryInterface; -use Webify\User\Authorization\Domain\ValueObject\{Permission, RoleId, RoleName, RoleSlug}; +use Webify\User\Context\Authorization\Domain\Collection\PermissionCollection; +use Webify\User\Context\Authorization\Domain\Entity\Role; +use Webify\User\Context\Authorization\Domain\Guard\RoleAlreadyExists; +use Webify\User\Context\Authorization\Domain\Repository\RoleRepositoryInterface; +use Webify\User\Context\Authorization\Domain\ValueObject\{Permission, RoleId, RoleName, RoleSlug}; /** * CrateRole service handles the creation of a new role. diff --git a/src/Authorization/Domain/Service/RevokeRole.php b/src/Context/Authorization/Application/Service/RevokeRole.php similarity index 83% rename from src/Authorization/Domain/Service/RevokeRole.php rename to src/Context/Authorization/Application/Service/RevokeRole.php index 2d53769..3c6ceb8 100644 --- a/src/Authorization/Domain/Service/RevokeRole.php +++ b/src/Context/Authorization/Application/Service/RevokeRole.php @@ -11,14 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Service; +namespace Webify\User\Context\Authorization\Application\Service; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authorization\Domain\Event\RoleRevoked; -use Webify\User\Authorization\Domain\Exception\RoleAssignmentNotFoundException; -use Webify\User\Authorization\Domain\Repository\RoleAssignmentRepositoryInterface; -use Webify\User\Authorization\Domain\ValueObject\RoleAssignmentId; +use Webify\User\Context\Authorization\Domain\Event\RoleRevoked; +use Webify\User\Context\Authorization\Domain\Exception\RoleAssignmentNotFoundException; +use Webify\User\Context\Authorization\Domain\Repository\RoleAssignmentRepositoryInterface; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleAssignmentId; /** * RevokeRole service for revoking roles from subjects. diff --git a/src/Authorization/Domain/Collection/PermissionCollection.php b/src/Context/Authorization/Domain/Collection/PermissionCollection.php similarity index 81% rename from src/Authorization/Domain/Collection/PermissionCollection.php rename to src/Context/Authorization/Domain/Collection/PermissionCollection.php index 290117f..5595847 100644 --- a/src/Authorization/Domain/Collection/PermissionCollection.php +++ b/src/Context/Authorization/Domain/Collection/PermissionCollection.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Collection; +namespace Webify\User\Context\Authorization\Domain\Collection; use Webify\Base\Contract\Collection\Collection; -use Webify\User\Authorization\Domain\ValueObject\Permission; +use Webify\User\Context\Authorization\Domain\ValueObject\Permission; /** * Permission collection. diff --git a/src/Authorization/Domain/Collection/RoleAssignmentCollection.php b/src/Context/Authorization/Domain/Collection/RoleAssignmentCollection.php similarity index 82% rename from src/Authorization/Domain/Collection/RoleAssignmentCollection.php rename to src/Context/Authorization/Domain/Collection/RoleAssignmentCollection.php index 7992a5b..229d40c 100644 --- a/src/Authorization/Domain/Collection/RoleAssignmentCollection.php +++ b/src/Context/Authorization/Domain/Collection/RoleAssignmentCollection.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Collection; +namespace Webify\User\Context\Authorization\Domain\Collection; use Webify\Base\Contract\Collection\Collection; -use Webify\User\Authorization\Domain\Entity\RoleAssignment; +use Webify\User\Context\Authorization\Domain\Entity\RoleAssignment; /** * Role assignment collection. diff --git a/src/Authorization/Domain/Entity/Role.php b/src/Context/Authorization/Domain/Entity/Role.php similarity index 89% rename from src/Authorization/Domain/Entity/Role.php rename to src/Context/Authorization/Domain/Entity/Role.php index daf738c..51ef7b9 100644 --- a/src/Authorization/Domain/Entity/Role.php +++ b/src/Context/Authorization/Domain/Entity/Role.php @@ -11,14 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Entity; +namespace Webify\User\Context\Authorization\Domain\Entity; use Webify\Base\Domain\Entity\AggregateRoot; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authorization\Domain\Collection\PermissionCollection; -use Webify\User\Authorization\Domain\Event\{PermissionGranted, PermissionRevoked, RoleCreated}; -use Webify\User\Authorization\Domain\Exception\SystemRoleModificationException; -use Webify\User\Authorization\Domain\ValueObject\{Permission, RoleId, RoleName, RoleSlug}; +use Webify\User\Context\Authorization\Domain\Collection\PermissionCollection; +use Webify\User\Context\Authorization\Domain\Event\{PermissionGranted, PermissionRevoked, RoleCreated}; +use Webify\User\Context\Authorization\Domain\Exception\SystemRoleModificationException; +use Webify\User\Context\Authorization\Domain\ValueObject\{Permission, RoleId, RoleName, RoleSlug}; /** * Role aggregate root. diff --git a/src/Authorization/Domain/Entity/RoleAssignment.php b/src/Context/Authorization/Domain/Entity/RoleAssignment.php similarity index 94% rename from src/Authorization/Domain/Entity/RoleAssignment.php rename to src/Context/Authorization/Domain/Entity/RoleAssignment.php index 1bc0311..9500dc4 100644 --- a/src/Authorization/Domain/Entity/RoleAssignment.php +++ b/src/Context/Authorization/Domain/Entity/RoleAssignment.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Entity; +namespace Webify\User\Context\Authorization\Domain\Entity; use Webify\Base\Domain\Entity\AggregateRoot; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authorization\Domain\Event\RoleAssigned; -use Webify\User\Authorization\Domain\ValueObject\{RoleAssignmentId, RoleId, SubjectId, TenantId}; +use Webify\User\Context\Authorization\Domain\Event\RoleAssigned; +use Webify\User\Context\Authorization\Domain\ValueObject\{RoleAssignmentId, RoleId, SubjectId, TenantId}; /** * Role assignment entity. diff --git a/src/Authorization/Domain/Event/PermissionGranted.php b/src/Context/Authorization/Domain/Event/PermissionGranted.php similarity index 95% rename from src/Authorization/Domain/Event/PermissionGranted.php rename to src/Context/Authorization/Domain/Event/PermissionGranted.php index 6779a58..2541a6f 100644 --- a/src/Authorization/Domain/Event/PermissionGranted.php +++ b/src/Context/Authorization/Domain/Event/PermissionGranted.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Event; +namespace Webify\User\Context\Authorization\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Authorization/Domain/Event/PermissionRevoked.php b/src/Context/Authorization/Domain/Event/PermissionRevoked.php similarity index 95% rename from src/Authorization/Domain/Event/PermissionRevoked.php rename to src/Context/Authorization/Domain/Event/PermissionRevoked.php index 7174bd6..2c2e72e 100644 --- a/src/Authorization/Domain/Event/PermissionRevoked.php +++ b/src/Context/Authorization/Domain/Event/PermissionRevoked.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Event; +namespace Webify\User\Context\Authorization\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Authorization/Domain/Event/RoleAssigned.php b/src/Context/Authorization/Domain/Event/RoleAssigned.php similarity index 94% rename from src/Authorization/Domain/Event/RoleAssigned.php rename to src/Context/Authorization/Domain/Event/RoleAssigned.php index 163922a..96e1418 100644 --- a/src/Authorization/Domain/Event/RoleAssigned.php +++ b/src/Context/Authorization/Domain/Event/RoleAssigned.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Event; +namespace Webify\User\Context\Authorization\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Authorization/Domain/Event/RoleCreated.php b/src/Context/Authorization/Domain/Event/RoleCreated.php similarity index 96% rename from src/Authorization/Domain/Event/RoleCreated.php rename to src/Context/Authorization/Domain/Event/RoleCreated.php index 6de4396..9216dc8 100644 --- a/src/Authorization/Domain/Event/RoleCreated.php +++ b/src/Context/Authorization/Domain/Event/RoleCreated.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Event; +namespace Webify\User\Context\Authorization\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Authorization/Domain/Event/RoleRevoked.php b/src/Context/Authorization/Domain/Event/RoleRevoked.php similarity index 94% rename from src/Authorization/Domain/Event/RoleRevoked.php rename to src/Context/Authorization/Domain/Event/RoleRevoked.php index 7bcd824..594f7cf 100644 --- a/src/Authorization/Domain/Event/RoleRevoked.php +++ b/src/Context/Authorization/Domain/Event/RoleRevoked.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Event; +namespace Webify\User\Context\Authorization\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Authorization/Domain/Exception/DuplicateRoleAssignmentException.php b/src/Context/Authorization/Domain/Exception/DuplicateRoleAssignmentException.php similarity index 96% rename from src/Authorization/Domain/Exception/DuplicateRoleAssignmentException.php rename to src/Context/Authorization/Domain/Exception/DuplicateRoleAssignmentException.php index 42b2137..52c1684 100644 --- a/src/Authorization/Domain/Exception/DuplicateRoleAssignmentException.php +++ b/src/Context/Authorization/Domain/Exception/DuplicateRoleAssignmentException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use DomainException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/InvalidRoleAssignmentIdException.php b/src/Context/Authorization/Domain/Exception/InvalidRoleAssignmentIdException.php similarity index 96% rename from src/Authorization/Domain/Exception/InvalidRoleAssignmentIdException.php rename to src/Context/Authorization/Domain/Exception/InvalidRoleAssignmentIdException.php index f66ef63..2ab9459 100644 --- a/src/Authorization/Domain/Exception/InvalidRoleAssignmentIdException.php +++ b/src/Context/Authorization/Domain/Exception/InvalidRoleAssignmentIdException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/InvalidRoleIdException.php b/src/Context/Authorization/Domain/Exception/InvalidRoleIdException.php similarity index 95% rename from src/Authorization/Domain/Exception/InvalidRoleIdException.php rename to src/Context/Authorization/Domain/Exception/InvalidRoleIdException.php index 1769a24..49bb867 100644 --- a/src/Authorization/Domain/Exception/InvalidRoleIdException.php +++ b/src/Context/Authorization/Domain/Exception/InvalidRoleIdException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/InvalidRoleNameException.php b/src/Context/Authorization/Domain/Exception/InvalidRoleNameException.php similarity index 95% rename from src/Authorization/Domain/Exception/InvalidRoleNameException.php rename to src/Context/Authorization/Domain/Exception/InvalidRoleNameException.php index 6d22f3d..a79ba3b 100644 --- a/src/Authorization/Domain/Exception/InvalidRoleNameException.php +++ b/src/Context/Authorization/Domain/Exception/InvalidRoleNameException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/InvalidRoleSlugException.php b/src/Context/Authorization/Domain/Exception/InvalidRoleSlugException.php similarity index 96% rename from src/Authorization/Domain/Exception/InvalidRoleSlugException.php rename to src/Context/Authorization/Domain/Exception/InvalidRoleSlugException.php index 71296d5..8960519 100644 --- a/src/Authorization/Domain/Exception/InvalidRoleSlugException.php +++ b/src/Context/Authorization/Domain/Exception/InvalidRoleSlugException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/InvalidSubjectIdException.php b/src/Context/Authorization/Domain/Exception/InvalidSubjectIdException.php similarity index 95% rename from src/Authorization/Domain/Exception/InvalidSubjectIdException.php rename to src/Context/Authorization/Domain/Exception/InvalidSubjectIdException.php index 09ab30a..c627328 100644 --- a/src/Authorization/Domain/Exception/InvalidSubjectIdException.php +++ b/src/Context/Authorization/Domain/Exception/InvalidSubjectIdException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/InvalidTenantIdException.php b/src/Context/Authorization/Domain/Exception/InvalidTenantIdException.php similarity index 95% rename from src/Authorization/Domain/Exception/InvalidTenantIdException.php rename to src/Context/Authorization/Domain/Exception/InvalidTenantIdException.php index 01143b1..01b0014 100644 --- a/src/Authorization/Domain/Exception/InvalidTenantIdException.php +++ b/src/Context/Authorization/Domain/Exception/InvalidTenantIdException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/PermissionValidationException.php b/src/Context/Authorization/Domain/Exception/PermissionValidationException.php similarity index 95% rename from src/Authorization/Domain/Exception/PermissionValidationException.php rename to src/Context/Authorization/Domain/Exception/PermissionValidationException.php index 321d102..cc65319 100644 --- a/src/Authorization/Domain/Exception/PermissionValidationException.php +++ b/src/Context/Authorization/Domain/Exception/PermissionValidationException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/RoleAlreadyExistsException.php b/src/Context/Authorization/Domain/Exception/RoleAlreadyExistsException.php similarity index 95% rename from src/Authorization/Domain/Exception/RoleAlreadyExistsException.php rename to src/Context/Authorization/Domain/Exception/RoleAlreadyExistsException.php index 1478606..76563f0 100644 --- a/src/Authorization/Domain/Exception/RoleAlreadyExistsException.php +++ b/src/Context/Authorization/Domain/Exception/RoleAlreadyExistsException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use DomainException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/RoleAssignmentNotFoundException.php b/src/Context/Authorization/Domain/Exception/RoleAssignmentNotFoundException.php similarity index 95% rename from src/Authorization/Domain/Exception/RoleAssignmentNotFoundException.php rename to src/Context/Authorization/Domain/Exception/RoleAssignmentNotFoundException.php index 67c9b5a..4055840 100644 --- a/src/Authorization/Domain/Exception/RoleAssignmentNotFoundException.php +++ b/src/Context/Authorization/Domain/Exception/RoleAssignmentNotFoundException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use RuntimeException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/RoleNotFoundException.php b/src/Context/Authorization/Domain/Exception/RoleNotFoundException.php similarity index 96% rename from src/Authorization/Domain/Exception/RoleNotFoundException.php rename to src/Context/Authorization/Domain/Exception/RoleNotFoundException.php index bdf625e..0d09a51 100644 --- a/src/Authorization/Domain/Exception/RoleNotFoundException.php +++ b/src/Context/Authorization/Domain/Exception/RoleNotFoundException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use RuntimeException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Exception/SystemRoleModificationException.php b/src/Context/Authorization/Domain/Exception/SystemRoleModificationException.php similarity index 95% rename from src/Authorization/Domain/Exception/SystemRoleModificationException.php rename to src/Context/Authorization/Domain/Exception/SystemRoleModificationException.php index e5bf77d..9f242b7 100644 --- a/src/Authorization/Domain/Exception/SystemRoleModificationException.php +++ b/src/Context/Authorization/Domain/Exception/SystemRoleModificationException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Exception; +namespace Webify\User\Context\Authorization\Domain\Exception; use DomainException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Authorization/Domain/Guard/DuplicateRoleAssignment.php b/src/Context/Authorization/Domain/Guard/DuplicateRoleAssignment.php similarity index 79% rename from src/Authorization/Domain/Guard/DuplicateRoleAssignment.php rename to src/Context/Authorization/Domain/Guard/DuplicateRoleAssignment.php index ebd6ef8..8d7850a 100644 --- a/src/Authorization/Domain/Guard/DuplicateRoleAssignment.php +++ b/src/Context/Authorization/Domain/Guard/DuplicateRoleAssignment.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Guard; +namespace Webify\User\Context\Authorization\Domain\Guard; -use Webify\User\Authorization\Domain\Exception\DuplicateRoleAssignmentException; -use Webify\User\Authorization\Domain\Repository\RoleAssignmentRepositoryInterface; -use Webify\User\Authorization\Domain\ValueObject\{RoleId, SubjectId, TenantId}; +use Webify\User\Context\Authorization\Domain\Exception\DuplicateRoleAssignmentException; +use Webify\User\Context\Authorization\Domain\Repository\RoleAssignmentRepositoryInterface; +use Webify\User\Context\Authorization\Domain\ValueObject\{RoleId, SubjectId, TenantId}; /** * Guard class to prevent duplicate role assignments. diff --git a/src/Authorization/Domain/Guard/RoleAlreadyExists.php b/src/Context/Authorization/Domain/Guard/RoleAlreadyExists.php similarity index 77% rename from src/Authorization/Domain/Guard/RoleAlreadyExists.php rename to src/Context/Authorization/Domain/Guard/RoleAlreadyExists.php index ef23618..b02c1fb 100644 --- a/src/Authorization/Domain/Guard/RoleAlreadyExists.php +++ b/src/Context/Authorization/Domain/Guard/RoleAlreadyExists.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Guard; +namespace Webify\User\Context\Authorization\Domain\Guard; -use Webify\User\Authorization\Domain\Exception\RoleAlreadyExistsException; -use Webify\User\Authorization\Domain\Repository\RoleRepositoryInterface; -use Webify\User\Authorization\Domain\ValueObject\RoleSlug; +use Webify\User\Context\Authorization\Domain\Exception\RoleAlreadyExistsException; +use Webify\User\Context\Authorization\Domain\Repository\RoleRepositoryInterface; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleSlug; /** * Guard class prevents against the creation of a role with a slug that already exists. diff --git a/src/Authorization/Domain/Repository/RoleAssignmentRepositoryInterface.php b/src/Context/Authorization/Domain/Repository/RoleAssignmentRepositoryInterface.php similarity index 85% rename from src/Authorization/Domain/Repository/RoleAssignmentRepositoryInterface.php rename to src/Context/Authorization/Domain/Repository/RoleAssignmentRepositoryInterface.php index afddfde..bea8af7 100644 --- a/src/Authorization/Domain/Repository/RoleAssignmentRepositoryInterface.php +++ b/src/Context/Authorization/Domain/Repository/RoleAssignmentRepositoryInterface.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Repository; +namespace Webify\User\Context\Authorization\Domain\Repository; -use Webify\User\Authorization\Domain\Collection\RoleAssignmentCollection; -use Webify\User\Authorization\Domain\Entity\RoleAssignment; -use Webify\User\Authorization\Domain\Exception\RoleAssignmentNotFoundException; -use Webify\User\Authorization\Domain\ValueObject\{RoleAssignmentId, RoleId, SubjectId, TenantId}; +use Webify\User\Context\Authorization\Domain\Collection\RoleAssignmentCollection; +use Webify\User\Context\Authorization\Domain\Entity\RoleAssignment; +use Webify\User\Context\Authorization\Domain\Exception\RoleAssignmentNotFoundException; +use Webify\User\Context\Authorization\Domain\ValueObject\{RoleAssignmentId, RoleId, SubjectId, TenantId}; /** * RoleAssignmentRepositoryInterface defines the contract for a role assignment repository. diff --git a/src/Authorization/Domain/Repository/RoleRepositoryInterface.php b/src/Context/Authorization/Domain/Repository/RoleRepositoryInterface.php similarity index 78% rename from src/Authorization/Domain/Repository/RoleRepositoryInterface.php rename to src/Context/Authorization/Domain/Repository/RoleRepositoryInterface.php index 19026f1..62b9d21 100644 --- a/src/Authorization/Domain/Repository/RoleRepositoryInterface.php +++ b/src/Context/Authorization/Domain/Repository/RoleRepositoryInterface.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Repository; +namespace Webify\User\Context\Authorization\Domain\Repository; -use Webify\User\Authorization\Domain\Entity\Role; -use Webify\User\Authorization\Domain\Exception\RoleNotFoundException; -use Webify\User\Authorization\Domain\ValueObject\{RoleId, RoleSlug}; +use Webify\User\Context\Authorization\Domain\Entity\Role; +use Webify\User\Context\Authorization\Domain\Exception\RoleNotFoundException; +use Webify\User\Context\Authorization\Domain\ValueObject\{RoleId, RoleSlug}; /** * RoleRepositoryInterface defines the contract for a role repository. diff --git a/src/Authorization/Domain/Service/Authorization.php b/src/Context/Authorization/Domain/Service/Authorization.php similarity index 89% rename from src/Authorization/Domain/Service/Authorization.php rename to src/Context/Authorization/Domain/Service/Authorization.php index f69b850..01ecc38 100644 --- a/src/Authorization/Domain/Service/Authorization.php +++ b/src/Context/Authorization/Domain/Service/Authorization.php @@ -11,16 +11,13 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\Service; +namespace Webify\User\Context\Authorization\Domain\Service; -use Webify\Base\Domain\Contract\Authorization\{ - AuthorizableResourceInterface, - AuthorizableSubjectInterface -}; +use Webify\Base\Domain\Contract\Authorization\{AuthorizableResourceInterface, AuthorizableSubjectInterface}; use Webify\Base\Domain\Contract\Authorization\Service\RuleRegistryInterface; -use Webify\User\Authorization\Domain\Exception\RoleNotFoundException; -use Webify\User\Authorization\Domain\Repository\{RoleAssignmentRepositoryInterface, RoleRepositoryInterface}; -use Webify\User\Authorization\Domain\ValueObject\{SubjectId, TenantId}; +use Webify\User\Context\Authorization\Domain\Exception\RoleNotFoundException; +use Webify\User\Context\Authorization\Domain\Repository\{RoleAssignmentRepositoryInterface, RoleRepositoryInterface}; +use Webify\User\Context\Authorization\Domain\ValueObject\{SubjectId, TenantId}; /** * Authorization class provides the implementation of the AuthorizationInterface. diff --git a/src/Authorization/Domain/ValueObject/Permission.php b/src/Context/Authorization/Domain/ValueObject/Permission.php similarity index 96% rename from src/Authorization/Domain/ValueObject/Permission.php rename to src/Context/Authorization/Domain/ValueObject/Permission.php index 33b5163..a4e9231 100644 --- a/src/Authorization/Domain/ValueObject/Permission.php +++ b/src/Context/Authorization/Domain/ValueObject/Permission.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\ValueObject; +namespace Webify\User\Context\Authorization\Domain\ValueObject; use JsonSerializable; -use Webify\User\Authorization\Domain\Exception\PermissionValidationException; +use Webify\User\Context\Authorization\Domain\Exception\PermissionValidationException; /** * Permission value object - Represent the atomic unit of access diff --git a/src/Authorization/Domain/ValueObject/RoleAssignmentId.php b/src/Context/Authorization/Domain/ValueObject/RoleAssignmentId.php similarity index 82% rename from src/Authorization/Domain/ValueObject/RoleAssignmentId.php rename to src/Context/Authorization/Domain/ValueObject/RoleAssignmentId.php index 59db018..97bc8b0 100644 --- a/src/Authorization/Domain/ValueObject/RoleAssignmentId.php +++ b/src/Context/Authorization/Domain/ValueObject/RoleAssignmentId.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\ValueObject; +namespace Webify\User\Context\Authorization\Domain\ValueObject; use Webify\Base\Domain\ValueObject\AggregateId; -use Webify\User\Authorization\Domain\Exception\InvalidRoleAssignmentIdException; +use Webify\User\Context\Authorization\Domain\Exception\InvalidRoleAssignmentIdException; /** * Role assignment ID value object. diff --git a/src/Authorization/Domain/ValueObject/RoleId.php b/src/Context/Authorization/Domain/ValueObject/RoleId.php similarity index 82% rename from src/Authorization/Domain/ValueObject/RoleId.php rename to src/Context/Authorization/Domain/ValueObject/RoleId.php index b8c053f..c92bdf4 100644 --- a/src/Authorization/Domain/ValueObject/RoleId.php +++ b/src/Context/Authorization/Domain/ValueObject/RoleId.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\ValueObject; +namespace Webify\User\Context\Authorization\Domain\ValueObject; use Webify\Base\Domain\ValueObject\AggregateId; -use Webify\User\Authorization\Domain\Exception\InvalidRoleIdException; +use Webify\User\Context\Authorization\Domain\Exception\InvalidRoleIdException; /** * Role ID value object. diff --git a/src/Authorization/Domain/ValueObject/RoleName.php b/src/Context/Authorization/Domain/ValueObject/RoleName.php similarity index 92% rename from src/Authorization/Domain/ValueObject/RoleName.php rename to src/Context/Authorization/Domain/ValueObject/RoleName.php index 8536a69..605f2ea 100644 --- a/src/Authorization/Domain/ValueObject/RoleName.php +++ b/src/Context/Authorization/Domain/ValueObject/RoleName.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\ValueObject; +namespace Webify\User\Context\Authorization\Domain\ValueObject; -use Webify\User\Authorization\Domain\Exception\InvalidRoleNameException; +use Webify\User\Context\Authorization\Domain\Exception\InvalidRoleNameException; /** * Role name value object. diff --git a/src/Authorization/Domain/ValueObject/RoleSlug.php b/src/Context/Authorization/Domain/ValueObject/RoleSlug.php similarity index 94% rename from src/Authorization/Domain/ValueObject/RoleSlug.php rename to src/Context/Authorization/Domain/ValueObject/RoleSlug.php index f247342..b0c9540 100644 --- a/src/Authorization/Domain/ValueObject/RoleSlug.php +++ b/src/Context/Authorization/Domain/ValueObject/RoleSlug.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\ValueObject; +namespace Webify\User\Context\Authorization\Domain\ValueObject; -use Webify\User\Authorization\Domain\Exception\InvalidRoleSlugException; +use Webify\User\Context\Authorization\Domain\Exception\InvalidRoleSlugException; /** * Role slug value object. diff --git a/src/Authorization/Domain/ValueObject/SubjectId.php b/src/Context/Authorization/Domain/ValueObject/SubjectId.php similarity index 82% rename from src/Authorization/Domain/ValueObject/SubjectId.php rename to src/Context/Authorization/Domain/ValueObject/SubjectId.php index 1c28a60..510c094 100644 --- a/src/Authorization/Domain/ValueObject/SubjectId.php +++ b/src/Context/Authorization/Domain/ValueObject/SubjectId.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\ValueObject; +namespace Webify\User\Context\Authorization\Domain\ValueObject; use Webify\Base\Domain\ValueObject\AggregateId; -use Webify\User\Authorization\Domain\Exception\InvalidSubjectIdException; +use Webify\User\Context\Authorization\Domain\Exception\InvalidSubjectIdException; /** * Subject ID value object. diff --git a/src/Authorization/Domain/ValueObject/TenantId.php b/src/Context/Authorization/Domain/ValueObject/TenantId.php similarity index 82% rename from src/Authorization/Domain/ValueObject/TenantId.php rename to src/Context/Authorization/Domain/ValueObject/TenantId.php index 987bf56..de06398 100644 --- a/src/Authorization/Domain/ValueObject/TenantId.php +++ b/src/Context/Authorization/Domain/ValueObject/TenantId.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Authorization\Domain\ValueObject; +namespace Webify\User\Context\Authorization\Domain\ValueObject; use Webify\Base\Domain\ValueObject\AggregateId; -use Webify\User\Authorization\Domain\Exception\InvalidTenantIdException; +use Webify\User\Context\Authorization\Domain\Exception\InvalidTenantIdException; /** * Tenant ID value object. diff --git a/src/Authentication/Domain/ValueObject/UserStatus.php b/src/Context/Authorization/Infrastructure/Container/ServiceDefinitions.php similarity index 53% rename from src/Authentication/Domain/ValueObject/UserStatus.php rename to src/Context/Authorization/Infrastructure/Container/ServiceDefinitions.php index b1b301e..b2ecd49 100644 --- a/src/Authentication/Domain/ValueObject/UserStatus.php +++ b/src/Context/Authorization/Infrastructure/Container/ServiceDefinitions.php @@ -11,21 +11,20 @@ */ declare(strict_types=1); -namespace Webify\User\Authentication\Domain\ValueObject; +namespace Webify\User\Context\Authorization\Infrastructure\Container; + +use Webify\Base\Infrastructure\Contract\DefinitionsInterface; /** - * The user status value object. + * Description. */ -enum UserStatus: string +final readonly class ServiceDefinitions implements DefinitionsInterface { - case Active = 'active'; - case Unverified = 'unverified'; - /** - * Check if the user is active. + * {@inheritDoc} */ - public function isActive(): bool + public static function getDefinitions(): array { - return self::Active === $this; + return []; } } diff --git a/src/Identity/Application/Query/User/FindAllUserInterface.php b/src/Context/Identity/Application/Query/User/FindAllUserInterface.php similarity index 79% rename from src/Identity/Application/Query/User/FindAllUserInterface.php rename to src/Context/Identity/Application/Query/User/FindAllUserInterface.php index 0d67f74..94797dd 100644 --- a/src/Identity/Application/Query/User/FindAllUserInterface.php +++ b/src/Context/Identity/Application/Query/User/FindAllUserInterface.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Application\Query\User; +namespace Webify\User\Context\Identity\Application\Query\User; /** * Query class defines the contract for a query to find all users. @@ -21,7 +21,7 @@ interface FindAllUserInterface /** * Retrieves a collection of all users. * - * @return UserCollection a collection containing all user entities + * @return UserCollection a collection containing all user-read models */ public function findAll(): UserCollection; } diff --git a/src/Identity/Application/Query/User/FindUserByEmailInterface.php b/src/Context/Identity/Application/Query/User/FindUserByEmailInterface.php similarity index 84% rename from src/Identity/Application/Query/User/FindUserByEmailInterface.php rename to src/Context/Identity/Application/Query/User/FindUserByEmailInterface.php index b0a1b37..7f8820b 100644 --- a/src/Identity/Application/Query/User/FindUserByEmailInterface.php +++ b/src/Context/Identity/Application/Query/User/FindUserByEmailInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Application\Query\User; +namespace Webify\User\Context\Identity\Application\Query\User; -use Webify\User\Identity\Domain\ValueObject\UserEmail; +use Webify\User\Context\Identity\Domain\ValueObject\UserEmail; /** * Query class defines the contract for a query to find a user by its identifier. diff --git a/src/Identity/Application/Query/User/FindUserByIdInterface.php b/src/Context/Identity/Application/Query/User/FindUserByIdInterface.php similarity index 86% rename from src/Identity/Application/Query/User/FindUserByIdInterface.php rename to src/Context/Identity/Application/Query/User/FindUserByIdInterface.php index 32e8d8a..dd92ba0 100644 --- a/src/Identity/Application/Query/User/FindUserByIdInterface.php +++ b/src/Context/Identity/Application/Query/User/FindUserByIdInterface.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Application\Query\User; +namespace Webify\User\Context\Identity\Application\Query\User; -use Webify\User\Identity\Domain\ValueObject\UserId; +use Webify\User\Domain\ValueObject\UserId; /** * Query class defines the contract for a query to find a user by its identifier. diff --git a/src/Identity/Application/Query/User/User.php b/src/Context/Identity/Application/Query/User/User.php similarity index 94% rename from src/Identity/Application/Query/User/User.php rename to src/Context/Identity/Application/Query/User/User.php index 42f77be..1d84724 100644 --- a/src/Identity/Application/Query/User/User.php +++ b/src/Context/Identity/Application/Query/User/User.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Application\Query\User; +namespace Webify\User\Context\Identity\Application\Query\User; /** * User read model. diff --git a/src/Identity/Application/Query/User/UserCollection.php b/src/Context/Identity/Application/Query/User/UserCollection.php similarity index 90% rename from src/Identity/Application/Query/User/UserCollection.php rename to src/Context/Identity/Application/Query/User/UserCollection.php index e002551..235ae31 100644 --- a/src/Identity/Application/Query/User/UserCollection.php +++ b/src/Context/Identity/Application/Query/User/UserCollection.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Application\Query\User; +namespace Webify\User\Context\Identity\Application\Query\User; use Webify\Base\Contract\Collection\Collection; diff --git a/src/Identity/Domain/Service/RegisterUser.php b/src/Context/Identity/Application/Service/RegisterUser.php similarity index 83% rename from src/Identity/Domain/Service/RegisterUser.php rename to src/Context/Identity/Application/Service/RegisterUser.php index 2b4f39f..3f16e9a 100644 --- a/src/Identity/Domain/Service/RegisterUser.php +++ b/src/Context/Identity/Application/Service/RegisterUser.php @@ -11,15 +11,16 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Service; +namespace Webify\User\Context\Identity\Application\Service; use Webify\Base\Domain\Contract\Identity\Service\PasswordHasherInterface; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; -use Webify\User\Identity\Domain\Entity\User; -use Webify\User\Identity\Domain\Guard\{EmailMustBeUnique, PasswordMustBeStrong}; -use Webify\User\Identity\Domain\Repository\UserRepositoryInterface; -use Webify\User\Identity\Domain\ValueObject\{DisplayName, PasswordHash, UserEmail, UserId}; +use Webify\User\Context\Identity\Domain\Entity\User; +use Webify\User\Context\Identity\Domain\Guard\{EmailMustBeUnique, PasswordMustBeStrong}; +use Webify\User\Context\Identity\Domain\Repository\UserRepositoryInterface; +use Webify\User\Context\Identity\Domain\ValueObject\{DisplayName, UserEmail}; +use Webify\User\Domain\ValueObject\{PasswordHash, UserId}; /** * RegisterUser service handles the user registering process. diff --git a/src/Identity/Domain/Service/UpdateUserEmail.php b/src/Context/Identity/Application/Service/UpdateUserEmail.php similarity index 82% rename from src/Identity/Domain/Service/UpdateUserEmail.php rename to src/Context/Identity/Application/Service/UpdateUserEmail.php index 0904abe..e773437 100644 --- a/src/Identity/Domain/Service/UpdateUserEmail.php +++ b/src/Context/Identity/Application/Service/UpdateUserEmail.php @@ -11,12 +11,13 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Service; +namespace Webify\User\Context\Identity\Application\Service; use Webify\Base\Domain\Event\DomainEventPublisherInterface; -use Webify\User\Identity\Domain\Guard\EmailMustBeUnique; -use Webify\User\Identity\Domain\Repository\UserRepositoryInterface; -use Webify\User\Identity\Domain\ValueObject\{UserEmail, UserId}; +use Webify\User\Context\Identity\Domain\Guard\EmailMustBeUnique; +use Webify\User\Context\Identity\Domain\Repository\UserRepositoryInterface; +use Webify\User\Context\Identity\Domain\ValueObject\UserEmail; +use Webify\User\Domain\ValueObject\UserId; /** * UpdateUserEmail service handles the user email update process. diff --git a/src/Identity/Domain/Service/UpdateUserPassword.php b/src/Context/Identity/Application/Service/UpdateUserPassword.php similarity index 85% rename from src/Identity/Domain/Service/UpdateUserPassword.php rename to src/Context/Identity/Application/Service/UpdateUserPassword.php index bbe53ef..75c3e0f 100644 --- a/src/Identity/Domain/Service/UpdateUserPassword.php +++ b/src/Context/Identity/Application/Service/UpdateUserPassword.php @@ -11,14 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Service; +namespace Webify\User\Context\Identity\Application\Service; use Webify\Base\Domain\Contract\Identity\Service\PasswordHasherInterface; use Webify\Base\Domain\Event\DomainEventPublisherInterface; -use Webify\User\Identity\Domain\Exception\CurrentPasswordNotMatchedException; -use Webify\User\Identity\Domain\Guard\PasswordMustBeStrong; -use Webify\User\Identity\Domain\Repository\UserRepositoryInterface; -use Webify\User\Identity\Domain\ValueObject\{PasswordHash, UserId}; +use Webify\User\Context\Identity\Domain\Exception\CurrentPasswordNotMatchedException; +use Webify\User\Context\Identity\Domain\Guard\PasswordMustBeStrong; +use Webify\User\Context\Identity\Domain\Repository\UserRepositoryInterface; +use Webify\User\Domain\ValueObject\{PasswordHash, UserId}; /** * UpdateUserPassword service handles the user password update process. diff --git a/src/Identity/Domain/Entity/User.php b/src/Context/Identity/Domain/Entity/User.php similarity index 90% rename from src/Identity/Domain/Entity/User.php rename to src/Context/Identity/Domain/Entity/User.php index 291631c..fb7922e 100644 --- a/src/Identity/Domain/Entity/User.php +++ b/src/Context/Identity/Domain/Entity/User.php @@ -11,21 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Entity; +namespace Webify\User\Context\Identity\Domain\Entity; use Webify\Base\Domain\Entity\AggregateRoot; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Identity\Domain\Event\{UserDisplayNameWasChanged, - UserEmailWasChanged, - UserPasswordWasChanged, - UserWasActivated, - UserWasDeactivated, - UserWasRegistered -}; -use Webify\User\Identity\Domain\Exception\{UserAlreadyActivatedException, - UserAlreadyDeactivatedException, - UserCannotBeDeactivatedException}; -use Webify\User\Identity\Domain\ValueObject\{DisplayName, PasswordHash, UserEmail, UserId, UserStatus}; +use Webify\User\Context\Identity\Domain\Event\{UserDisplayNameWasChanged, UserEmailWasChanged, UserPasswordWasChanged, UserWasActivated, UserWasDeactivated, UserWasRegistered}; +use Webify\User\Context\Identity\Domain\Exception\{UserAlreadyActivatedException, UserAlreadyDeactivatedException, UserCannotBeDeactivatedException}; +use Webify\User\Context\Identity\Domain\ValueObject\{DisplayName, UserEmail}; +use Webify\User\Domain\ValueObject\{PasswordHash, UserId, UserStatus}; /** * User aggregate root. diff --git a/src/Identity/Domain/Event/UserDisplayNameWasChanged.php b/src/Context/Identity/Domain/Event/UserDisplayNameWasChanged.php similarity index 94% rename from src/Identity/Domain/Event/UserDisplayNameWasChanged.php rename to src/Context/Identity/Domain/Event/UserDisplayNameWasChanged.php index 462e6ec..b145dc1 100644 --- a/src/Identity/Domain/Event/UserDisplayNameWasChanged.php +++ b/src/Context/Identity/Domain/Event/UserDisplayNameWasChanged.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Event; +namespace Webify\User\Context\Identity\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Identity/Domain/Event/UserEmailWasChanged.php b/src/Context/Identity/Domain/Event/UserEmailWasChanged.php similarity index 94% rename from src/Identity/Domain/Event/UserEmailWasChanged.php rename to src/Context/Identity/Domain/Event/UserEmailWasChanged.php index b486382..3675e3a 100644 --- a/src/Identity/Domain/Event/UserEmailWasChanged.php +++ b/src/Context/Identity/Domain/Event/UserEmailWasChanged.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Event; +namespace Webify\User\Context\Identity\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Identity/Domain/Event/UserPasswordWasChanged.php b/src/Context/Identity/Domain/Event/UserPasswordWasChanged.php similarity index 94% rename from src/Identity/Domain/Event/UserPasswordWasChanged.php rename to src/Context/Identity/Domain/Event/UserPasswordWasChanged.php index 1c66073..160ca93 100644 --- a/src/Identity/Domain/Event/UserPasswordWasChanged.php +++ b/src/Context/Identity/Domain/Event/UserPasswordWasChanged.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Event; +namespace Webify\User\Context\Identity\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Identity/Domain/Event/UserWasActivated.php b/src/Context/Identity/Domain/Event/UserWasActivated.php similarity index 94% rename from src/Identity/Domain/Event/UserWasActivated.php rename to src/Context/Identity/Domain/Event/UserWasActivated.php index bd3af54..6de3343 100644 --- a/src/Identity/Domain/Event/UserWasActivated.php +++ b/src/Context/Identity/Domain/Event/UserWasActivated.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Event; +namespace Webify\User\Context\Identity\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Identity/Domain/Event/UserWasDeactivated.php b/src/Context/Identity/Domain/Event/UserWasDeactivated.php similarity index 94% rename from src/Identity/Domain/Event/UserWasDeactivated.php rename to src/Context/Identity/Domain/Event/UserWasDeactivated.php index 8f05c6a..c6dace3 100644 --- a/src/Identity/Domain/Event/UserWasDeactivated.php +++ b/src/Context/Identity/Domain/Event/UserWasDeactivated.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Event; +namespace Webify\User\Context\Identity\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Identity/Domain/Event/UserWasRegistered.php b/src/Context/Identity/Domain/Event/UserWasRegistered.php similarity index 94% rename from src/Identity/Domain/Event/UserWasRegistered.php rename to src/Context/Identity/Domain/Event/UserWasRegistered.php index 18e4f67..5e353a9 100644 --- a/src/Identity/Domain/Event/UserWasRegistered.php +++ b/src/Context/Identity/Domain/Event/UserWasRegistered.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Event; +namespace Webify\User\Context\Identity\Domain\Event; use DateTimeImmutable; use Webify\Base\Domain\Event\DomainEventInterface; diff --git a/src/Identity/Domain/Exception/CurrentPasswordNotMatchedException.php b/src/Context/Identity/Domain/Exception/CurrentPasswordNotMatchedException.php similarity index 96% rename from src/Identity/Domain/Exception/CurrentPasswordNotMatchedException.php rename to src/Context/Identity/Domain/Exception/CurrentPasswordNotMatchedException.php index ecceacb..400a798 100644 --- a/src/Identity/Domain/Exception/CurrentPasswordNotMatchedException.php +++ b/src/Context/Identity/Domain/Exception/CurrentPasswordNotMatchedException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Context\Identity\Domain\Exception; use DomainException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Identity/Domain/Exception/EmailMustBeUniqueException.php b/src/Context/Identity/Domain/Exception/EmailMustBeUniqueException.php similarity index 96% rename from src/Identity/Domain/Exception/EmailMustBeUniqueException.php rename to src/Context/Identity/Domain/Exception/EmailMustBeUniqueException.php index d22be68..f932809 100644 --- a/src/Identity/Domain/Exception/EmailMustBeUniqueException.php +++ b/src/Context/Identity/Domain/Exception/EmailMustBeUniqueException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Context\Identity\Domain\Exception; use DomainException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Identity/Domain/Exception/InvalidDisplayNameException.php b/src/Context/Identity/Domain/Exception/InvalidDisplayNameException.php similarity index 96% rename from src/Identity/Domain/Exception/InvalidDisplayNameException.php rename to src/Context/Identity/Domain/Exception/InvalidDisplayNameException.php index 6406608..2093af5 100644 --- a/src/Identity/Domain/Exception/InvalidDisplayNameException.php +++ b/src/Context/Identity/Domain/Exception/InvalidDisplayNameException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Context\Identity\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Identity/Domain/Exception/InvalidUserEmailException.php b/src/Context/Identity/Domain/Exception/InvalidUserEmailException.php similarity index 96% rename from src/Identity/Domain/Exception/InvalidUserEmailException.php rename to src/Context/Identity/Domain/Exception/InvalidUserEmailException.php index a710e70..a665700 100644 --- a/src/Identity/Domain/Exception/InvalidUserEmailException.php +++ b/src/Context/Identity/Domain/Exception/InvalidUserEmailException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Context\Identity\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Identity/Domain/Exception/UserAlreadyActivatedException.php b/src/Context/Identity/Domain/Exception/UserAlreadyActivatedException.php similarity index 96% rename from src/Identity/Domain/Exception/UserAlreadyActivatedException.php rename to src/Context/Identity/Domain/Exception/UserAlreadyActivatedException.php index 9e10369..6c6a29d 100644 --- a/src/Identity/Domain/Exception/UserAlreadyActivatedException.php +++ b/src/Context/Identity/Domain/Exception/UserAlreadyActivatedException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Context\Identity\Domain\Exception; use LogicException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Identity/Domain/Exception/UserAlreadyDeactivatedException.php b/src/Context/Identity/Domain/Exception/UserAlreadyDeactivatedException.php similarity index 96% rename from src/Identity/Domain/Exception/UserAlreadyDeactivatedException.php rename to src/Context/Identity/Domain/Exception/UserAlreadyDeactivatedException.php index 08d086e..a908886 100644 --- a/src/Identity/Domain/Exception/UserAlreadyDeactivatedException.php +++ b/src/Context/Identity/Domain/Exception/UserAlreadyDeactivatedException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Context\Identity\Domain\Exception; use LogicException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Identity/Domain/Exception/UserCannotBeDeactivatedException.php b/src/Context/Identity/Domain/Exception/UserCannotBeDeactivatedException.php similarity index 96% rename from src/Identity/Domain/Exception/UserCannotBeDeactivatedException.php rename to src/Context/Identity/Domain/Exception/UserCannotBeDeactivatedException.php index a1680d1..e84e8a4 100644 --- a/src/Identity/Domain/Exception/UserCannotBeDeactivatedException.php +++ b/src/Context/Identity/Domain/Exception/UserCannotBeDeactivatedException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Context\Identity\Domain\Exception; use LogicException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Identity/Domain/Exception/UserNotFoundException.php b/src/Context/Identity/Domain/Exception/UserNotFoundException.php similarity index 96% rename from src/Identity/Domain/Exception/UserNotFoundException.php rename to src/Context/Identity/Domain/Exception/UserNotFoundException.php index 2673e03..fc998d9 100644 --- a/src/Identity/Domain/Exception/UserNotFoundException.php +++ b/src/Context/Identity/Domain/Exception/UserNotFoundException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Context\Identity\Domain\Exception; use RuntimeException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Identity/Domain/Exception/WeakPasswordException.php b/src/Context/Identity/Domain/Exception/WeakPasswordException.php similarity index 98% rename from src/Identity/Domain/Exception/WeakPasswordException.php rename to src/Context/Identity/Domain/Exception/WeakPasswordException.php index 8994ab6..c98f8b4 100644 --- a/src/Identity/Domain/Exception/WeakPasswordException.php +++ b/src/Context/Identity/Domain/Exception/WeakPasswordException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Context\Identity\Domain\Exception; use DomainException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; diff --git a/src/Identity/Domain/Guard/EmailMustBeUnique.php b/src/Context/Identity/Domain/Guard/EmailMustBeUnique.php similarity index 76% rename from src/Identity/Domain/Guard/EmailMustBeUnique.php rename to src/Context/Identity/Domain/Guard/EmailMustBeUnique.php index c0ae239..88476e7 100644 --- a/src/Identity/Domain/Guard/EmailMustBeUnique.php +++ b/src/Context/Identity/Domain/Guard/EmailMustBeUnique.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Guard; +namespace Webify\User\Context\Identity\Domain\Guard; -use Webify\User\Identity\Domain\Exception\EmailMustBeUniqueException; -use Webify\User\Identity\Domain\Repository\UserRepositoryInterface; -use Webify\User\Identity\Domain\ValueObject\UserEmail; +use Webify\User\Context\Identity\Domain\Exception\EmailMustBeUniqueException; +use Webify\User\Context\Identity\Domain\Repository\UserRepositoryInterface; +use Webify\User\Context\Identity\Domain\ValueObject\UserEmail; /** * Guard prevents against the user registration with existed registered email. diff --git a/src/Identity/Domain/Guard/PasswordMustBeStrong.php b/src/Context/Identity/Domain/Guard/PasswordMustBeStrong.php similarity index 90% rename from src/Identity/Domain/Guard/PasswordMustBeStrong.php rename to src/Context/Identity/Domain/Guard/PasswordMustBeStrong.php index 8c54645..4c7c3cc 100644 --- a/src/Identity/Domain/Guard/PasswordMustBeStrong.php +++ b/src/Context/Identity/Domain/Guard/PasswordMustBeStrong.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Guard; +namespace Webify\User\Context\Identity\Domain\Guard; -use Webify\User\Identity\Domain\Exception\WeakPasswordException; -use Webify\User\Identity\Domain\Policy\PasswordPolicy; +use Webify\User\Context\Identity\Domain\Exception\WeakPasswordException; +use Webify\User\Context\Identity\Domain\Policy\PasswordPolicy; /** * Guard prevents against the weak password. diff --git a/src/Identity/Domain/Policy/PasswordPolicy.php b/src/Context/Identity/Domain/Policy/PasswordPolicy.php similarity index 98% rename from src/Identity/Domain/Policy/PasswordPolicy.php rename to src/Context/Identity/Domain/Policy/PasswordPolicy.php index d92cbc0..dd0f116 100644 --- a/src/Identity/Domain/Policy/PasswordPolicy.php +++ b/src/Context/Identity/Domain/Policy/PasswordPolicy.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Policy; +namespace Webify\User\Context\Identity\Domain\Policy; /** * Represents a password policy that validates passwords against specific criteria. diff --git a/src/Identity/Domain/Repository/UserRepositoryInterface.php b/src/Context/Identity/Domain/Repository/UserRepositoryInterface.php similarity index 79% rename from src/Identity/Domain/Repository/UserRepositoryInterface.php rename to src/Context/Identity/Domain/Repository/UserRepositoryInterface.php index 27f687c..21c82cf 100644 --- a/src/Identity/Domain/Repository/UserRepositoryInterface.php +++ b/src/Context/Identity/Domain/Repository/UserRepositoryInterface.php @@ -11,11 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Repository; +namespace Webify\User\Context\Identity\Domain\Repository; -use Webify\User\Identity\Domain\Entity\User; -use Webify\User\Identity\Domain\Exception\UserNotFoundException; -use Webify\User\Identity\Domain\ValueObject\{UserEmail, UserId}; +use Webify\User\Context\Identity\Domain\Entity\User; +use Webify\User\Context\Identity\Domain\Exception\UserNotFoundException; +use Webify\User\Context\Identity\Domain\ValueObject\UserEmail; +use Webify\User\Domain\ValueObject\UserId; /** * UserRepositoryInterface defines the contract for a user repository. diff --git a/src/Identity/Domain/ValueObject/DisplayName.php b/src/Context/Identity/Domain/ValueObject/DisplayName.php similarity index 93% rename from src/Identity/Domain/ValueObject/DisplayName.php rename to src/Context/Identity/Domain/ValueObject/DisplayName.php index da4612e..058e9e3 100644 --- a/src/Identity/Domain/ValueObject/DisplayName.php +++ b/src/Context/Identity/Domain/ValueObject/DisplayName.php @@ -11,9 +11,9 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\ValueObject; +namespace Webify\User\Context\Identity\Domain\ValueObject; -use Webify\User\Identity\Domain\Exception\InvalidDisplayNameException; +use Webify\User\Context\Identity\Domain\Exception\InvalidDisplayNameException; /** * DisplayName value object represents the display name of a user. diff --git a/src/Identity/Domain/ValueObject/UserEmail.php b/src/Context/Identity/Domain/ValueObject/UserEmail.php similarity index 85% rename from src/Identity/Domain/ValueObject/UserEmail.php rename to src/Context/Identity/Domain/ValueObject/UserEmail.php index 5619d44..bfd86ad 100644 --- a/src/Identity/Domain/ValueObject/UserEmail.php +++ b/src/Context/Identity/Domain/ValueObject/UserEmail.php @@ -11,10 +11,10 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\ValueObject; +namespace Webify\User\Context\Identity\Domain\ValueObject; use Webify\Base\Domain\ValueObject\Email; -use Webify\User\Identity\Domain\Exception\InvalidUserEmailException; +use Webify\User\Context\Identity\Domain\Exception\InvalidUserEmailException; /** * User email value object. diff --git a/src/Context/Identity/Infrastructure/Container/ServiceDefinitions.php b/src/Context/Identity/Infrastructure/Container/ServiceDefinitions.php new file mode 100644 index 0000000..ce41bf5 --- /dev/null +++ b/src/Context/Identity/Infrastructure/Container/ServiceDefinitions.php @@ -0,0 +1,36 @@ + + */ +declare(strict_types=1); + +namespace Webify\User\Context\Identity\Infrastructure\Container; + +use Webify\Base\Domain\Contract\Identity\Service\PasswordHasherInterface; +use Webify\Base\Infrastructure\Contract\DefinitionsInterface; +use Webify\User\Context\Identity\Infrastructure\Service\PasswordHasher; + +use function DI\create; + +/** + * Description. + */ +final readonly class ServiceDefinitions implements DefinitionsInterface +{ + /** + * {@inheritDoc} + */ + public static function getDefinitions(): array + { + return [ + PasswordHasherInterface::class => create(PasswordHasher::class), + ]; + } +} diff --git a/src/Identity/Infrastructure/Exception/FailedToHashPasswordException.php b/src/Context/Identity/Infrastructure/Exception/FailedToHashPasswordException.php similarity index 95% rename from src/Identity/Infrastructure/Exception/FailedToHashPasswordException.php rename to src/Context/Identity/Infrastructure/Exception/FailedToHashPasswordException.php index dc76b89..7403067 100644 --- a/src/Identity/Infrastructure/Exception/FailedToHashPasswordException.php +++ b/src/Context/Identity/Infrastructure/Exception/FailedToHashPasswordException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Infrastructure\Exception; +namespace Webify\User\Context\Identity\Infrastructure\Exception; use RuntimeException; use Throwable; diff --git a/src/Identity/Infrastructure/Service/PasswordHasher.php b/src/Context/Identity/Infrastructure/Service/PasswordHasher.php similarity index 81% rename from src/Identity/Infrastructure/Service/PasswordHasher.php rename to src/Context/Identity/Infrastructure/Service/PasswordHasher.php index 7a20d9c..05fabd5 100644 --- a/src/Identity/Infrastructure/Service/PasswordHasher.php +++ b/src/Context/Identity/Infrastructure/Service/PasswordHasher.php @@ -11,11 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Infrastructure\Service; +namespace Webify\User\Context\Identity\Infrastructure\Service; use ValueError; use Webify\Base\Domain\Contract\Identity\Service\PasswordHasherInterface; -use Webify\User\Identity\Infrastructure\Exception\FailedToHashPasswordException; +use Webify\User\Context\Identity\Infrastructure\Exception\FailedToHashPasswordException; + +use function password_hash; +use function password_verify; /** * The implementation for the password hashing service. diff --git a/src/Identity/Domain/Exception/InvalidPasswordHashException.php b/src/Domain/Exception/InvalidPasswordHashException.php similarity index 91% rename from src/Identity/Domain/Exception/InvalidPasswordHashException.php rename to src/Domain/Exception/InvalidPasswordHashException.php index 4d18d7b..2dc5aac 100644 --- a/src/Identity/Domain/Exception/InvalidPasswordHashException.php +++ b/src/Domain/Exception/InvalidPasswordHashException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; @@ -19,6 +19,8 @@ /** * Exception thrown when an invalid password hash value is encountered. + * + * This exception belongs to the shared kernel because `PasswordHash` is shared by every context. */ final class InvalidPasswordHashException extends InvalidArgumentException implements TranslatableExceptionInterface { diff --git a/src/Identity/Domain/Exception/InvalidUserIdException.php b/src/Domain/Exception/InvalidUserIdException.php similarity index 91% rename from src/Identity/Domain/Exception/InvalidUserIdException.php rename to src/Domain/Exception/InvalidUserIdException.php index 74ef70b..4988541 100644 --- a/src/Identity/Domain/Exception/InvalidUserIdException.php +++ b/src/Domain/Exception/InvalidUserIdException.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\Exception; +namespace Webify\User\Domain\Exception; use InvalidArgumentException; use Webify\Base\Contract\Exception\TranslatableExceptionInterface; @@ -19,6 +19,8 @@ /** * Exception thrown when an invalid user id value is encountered. + * + * This exception belongs to the shared kernel because `UserId` is shared by every context. */ final class InvalidUserIdException extends InvalidArgumentException implements TranslatableExceptionInterface { diff --git a/src/Identity/Domain/ValueObject/PasswordHash.php b/src/Domain/ValueObject/PasswordHash.php similarity index 55% rename from src/Identity/Domain/ValueObject/PasswordHash.php rename to src/Domain/ValueObject/PasswordHash.php index 73e3e16..d4d5639 100644 --- a/src/Identity/Domain/ValueObject/PasswordHash.php +++ b/src/Domain/ValueObject/PasswordHash.php @@ -11,12 +11,26 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\ValueObject; +namespace Webify\User\Domain\ValueObject; -use Webify\User\Identity\Domain\Exception\InvalidPasswordHashException; +use Webify\User\Domain\Exception\InvalidPasswordHashException; + +use function password_get_info; /** * Password hash value object. + * + * Produced by Identity and consumed by Authentication, so it lives in the shared kernel. + * + * The invariant is that the wrapped value is a hash produced by a PHP password hashing + * algorithm, which is what makes it safe to hand straight to `password_verify()`. An empty + * value, a plaintext password, a truncated row, or a value carrying stray surrounding + * whitespace is rejected rather than silently accepted, because each of those means the + * stored data is wrong and swallowing it would hide that. + * + * Validity is decided by `password_get_info()`, so it recognises exactly the algorithms PHP + * supports. If a non-PHP hasher is ever adopted — a legacy `scrypt`/`pbkdf2` column, or a + * remote hashing service — this check has to be widened alongside it. */ final readonly class PasswordHash { @@ -68,13 +82,16 @@ public function equals(self $other): bool /** * Validates the password hash value. + * + * A recognised algorithm is the signal that the value is a real hash: `algo` is null for + * anything PHP does not recognise, including plaintext and malformed input. */ private function isValid(): bool { - if (empty($this->value)) { + if ('' === $this->value) { return false; } - return true; + return null !== password_get_info($this->value)['algo']; } } diff --git a/src/Identity/Domain/ValueObject/UserId.php b/src/Domain/ValueObject/UserId.php similarity index 71% rename from src/Identity/Domain/ValueObject/UserId.php rename to src/Domain/ValueObject/UserId.php index c4c8d8f..f987f4b 100644 --- a/src/Identity/Domain/ValueObject/UserId.php +++ b/src/Domain/ValueObject/UserId.php @@ -11,13 +11,16 @@ */ declare(strict_types=1); -namespace Webify\User\Identity\Domain\ValueObject; +namespace Webify\User\Domain\ValueObject; use Webify\Base\Domain\ValueObject\AggregateId; -use Webify\User\Identity\Domain\Exception\InvalidUserIdException; +use Webify\User\Domain\Exception\InvalidUserIdException; /** * The user ID value object. + * + * Shared by every context, so it lives in the shared kernel. Identity owns the user aggregate + * and is therefore the canonical home of the user id translation group. */ final readonly class UserId extends AggregateId { diff --git a/src/Domain/ValueObject/UserStatus.php b/src/Domain/ValueObject/UserStatus.php new file mode 100644 index 0000000..0aa573b --- /dev/null +++ b/src/Domain/ValueObject/UserStatus.php @@ -0,0 +1,84 @@ + + */ +declare(strict_types=1); + +namespace Webify\User\Domain\ValueObject; + +/** + * The user status value object. + * + * Shared by every context, so it lives in the shared kernel. This enum is the reconciliation of + * two previously diverged copies: + * + * - Identity owned `Active`, `Inactive`, `Deactivated` — the lifecycle of the user aggregate. + * - Authentication owned `Active`, `Unverified` — only the subset it needs to gate logins. + * + * Both sets are preserved here so neither context loses a case it depends on. + */ +enum UserStatus: string +{ + case Active = 'active'; + case Inactive = 'inactive'; + case Deactivated = 'deactivated'; + case Unverified = 'unverified'; + + /** + * Resolves a stored status string to the corresponding status. + * + * Status reaches the boundaries as a plain string — `UserCredentials::$status` is a string, + * as is a column read from persistence — so this is the step that turns it back into a + * real type. + * + * An unrecognised value resolves to {@see self::Unverified} rather than throwing. A status + * the system cannot read means the data is not understood, and failing closed on that keeps + * a guard from admitting a user whose state is unknown. Throwing instead would turn one + * unexpected row into an unhandled error escaping whatever flow happened to read it. + * + * @param string $status the stored status, such as 'active' + */ + public static function fromString(string $status): self + { + return self::tryFrom($status) ?? self::Unverified; + } + + /** + * Check if the user is active. + */ + public function isActive(): bool + { + return self::Active === $this; + } + + /** + * Check if the user is inactive. + */ + public function isInactive(): bool + { + return self::Inactive === $this; + } + + /** + * Check if the user is deactivated. + */ + public function isDeactivated(): bool + { + return self::Deactivated === $this; + } + + /** + * Check if the user is unverified. + */ + public function isUnverified(): bool + { + return self::Unverified === $this; + } +} diff --git a/src/Identity/Domain/ValueObject/UserStatus.php b/src/Identity/Domain/ValueObject/UserStatus.php deleted file mode 100644 index ae6080b..0000000 --- a/src/Identity/Domain/ValueObject/UserStatus.php +++ /dev/null @@ -1,48 +0,0 @@ - - */ -declare(strict_types=1); - -namespace Webify\User\Identity\Domain\ValueObject; - -/** - * The user status value object. - */ -enum UserStatus: string -{ - case Active = 'active'; - case Inactive = 'inactive'; - case Deactivated = 'deactivated'; - - /** - * Check if the user is active. - */ - public function isActive(): bool - { - return self::Active === $this; - } - - /** - * Check if the user is inactive. - */ - public function isInactive(): bool - { - return self::Inactive === $this; - } - - /** - * Check if the user is deactivated. - */ - public function isDeactivated(): bool - { - return self::Deactivated === $this; - } -} diff --git a/src/Infrastructure/Extension/UserExtension.php b/src/Infrastructure/Extension/UserExtension.php new file mode 100644 index 0000000..5970c6b --- /dev/null +++ b/src/Infrastructure/Extension/UserExtension.php @@ -0,0 +1,95 @@ + + */ +declare(strict_types=1); + +namespace Webify\User\Infrastructure\Extension; + +use Webify\Base\Domain\ValueObject\TemplatePath; +use Webify\Base\Infrastructure\Contract\{AssetsProviderInterface, ExtensionInterface}; +use Webify\User\Infrastructure\Provider\UserService; + +/** + * The user extension. + */ +final readonly class UserExtension implements ExtensionInterface +{ + /** + * @var string the root path of the extension + */ + private string $rootPath; + + /** + * The constructor. + */ + public function __construct() + { + $this->rootPath = dirname(__DIR__, 3); + } + + /** + * {@inheritDoc} + */ + public function getId(): string + { + return 'webifycms-user'; + } + + /** + * {@inheritDoc} + */ + public function getName(): string + { + return 'WebifyCMS User Extension'; + } + + /** + * {@inheritDoc} + */ + public function getProviders(): array + { + return [ + new UserService(), + ]; + } + + /** + * {@inheritDoc} + */ + public function getVersion(): string + { + return '0.2.0-beta'; + } + + /** + * {@inheritDoc} + */ + public function getSlug(): string + { + return 'webifycms-user'; + } + + /** + * {@inheritDoc} + */ + public function getTemplatePath(): TemplatePath + { + return TemplatePath::fromString($this->rootPath . DIRECTORY_SEPARATOR . 'templates'); + } + + /** + * {@inheritDoc} + */ + public function getAssetsProvider(): ?AssetsProviderInterface + { + return null; + } +} diff --git a/src/Infrastructure/Provider/UserService.php b/src/Infrastructure/Provider/UserService.php new file mode 100644 index 0000000..6de56ea --- /dev/null +++ b/src/Infrastructure/Provider/UserService.php @@ -0,0 +1,37 @@ + + */ +declare(strict_types=1); + +namespace Webify\User\Infrastructure\Provider; + +use Webify\Base\Infrastructure\Contract\ServiceProviderInterface; +use Webify\User\Context\Authentication\Infrastructure\Container\ServiceDefinitions as AuthenticationServiceDefinitions; +use Webify\User\Context\Authorization\Infrastructure\Container\ServiceDefinitions as AuthorizationServiceDefinitions; +use Webify\User\Context\Identity\Infrastructure\Container\ServiceDefinitions as IdentityServiceDefinitions; + +/** + * The user service provider. + */ +final readonly class UserService implements ServiceProviderInterface +{ + /** + * {@inheritDoc} + */ + public function getDefinitions(): array + { + return [ + ...AuthenticationServiceDefinitions::getDefinitions(), + ...AuthorizationServiceDefinitions::getDefinitions(), + ...IdentityServiceDefinitions::getDefinitions(), + ]; + } +} diff --git a/test/Architecture/AuthenticationSpecification.php b/test/Architecture/AuthenticationSpecification.php index a84a0e2..3509ae7 100644 --- a/test/Architecture/AuthenticationSpecification.php +++ b/test/Architecture/AuthenticationSpecification.php @@ -19,11 +19,10 @@ use PHPat\Test\PHPat; /** - * Architecture tests that enforce DDD and clean architecture principles. + * Architecture tests for the Authentication context. * * Domain is the innermost layer — it must not know about Application or Infrastructure. * Application sits between Domain and Infrastructure. - * Contract is a shared kernel that can be referenced by all layers. * Infrastructure implements Domain interfaces (Dependency Inversion). * * @internal @@ -32,50 +31,39 @@ final class AuthenticationSpecification { /** * Domain classes must not depend on Application or Infrastructure. - * Dependency on Contract (shared kernel) is permitted. + * + * The authentication strategies (`PasswordBase`, `ChallengeBase`, + * `ChallengeCodeStrategy`, `ChallengeTokenStrategy`) live in `Authentication\Application` + * precisely because they orchestrate use cases; keeping them here would invert the + * dependency direction. */ public function testDomainDoesNotDependOnApplicationOrInfrastructure(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Authentication\Authentication\Domain')) + ->classes(Selector::inNamespace('Webify\User\Context\Authentication\Domain')) ->shouldNot() ->dependOn() ->classes( - Selector::inNamespace('Webify\User\Authentication\Application'), - Selector::inNamespace('Webify\User\Authentication\Infrastructure'), + Selector::inNamespace('Webify\User\Context\Authentication\Application'), + Selector::inNamespace('Webify\User\Context\Authentication\Infrastructure'), ) ->because('Domain is the innermost layer and must not depend on outer layers') ; } - /** - * Contract must not depend on Application or Infrastructure. - * It may reference Domain types. - */ - public function testContractDoesNotDependOnApplicationOrInfrastructure(): Rule - { - return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Authentication\Contract')) - ->shouldNot() - ->dependOn() - ->classes( - Selector::inNamespace('Webify\User\Authentication\Application'), - Selector::inNamespace('Webify\User\Authentication\Infrastructure'), - ) - ->because('Contract must not depend on outer layers') - ; - } - /** * Application classes must not depend on Infrastructure classes. + * + * NOTE: live today — `Authentication\Application\Query`, `Application\Service` and + * `Application\Strategy` are populated, so a violation here fails `composer analyse`. */ public function testApplicationDoesNotDependOnInfrastructure(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Authentication\Application')) + ->classes(Selector::inNamespace('Webify\User\Context\Authentication\Application')) ->shouldNot() ->dependOn() - ->classes(Selector::inNamespace('Webify\User\Authentication\Infrastructure')) + ->classes(Selector::inNamespace('Webify\User\Context\Authentication\Infrastructure')) ->because('Application should not depend on Infrastructure details') ; } @@ -86,7 +74,7 @@ public function testApplicationDoesNotDependOnInfrastructure(): Rule public function testDomainExceptionsExtendException(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Authentication\Domain\Exception')) + ->classes(Selector::inNamespace('Webify\User\Context\Authentication\Domain\Exception')) ->should() ->extend() ->classes(Selector::classname(Exception::class)) @@ -100,7 +88,7 @@ public function testDomainExceptionsExtendException(): Rule public function testInfrastructureExceptionsExtendException(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Authentication\Infrastructure\Exception')) + ->classes(Selector::inNamespace('Webify\User\Context\Authentication\Infrastructure\Exception')) ->should() ->extend() ->classes(Selector::classname(Exception::class)) diff --git a/test/Architecture/AuthorizationSpecification.php b/test/Architecture/AuthorizationSpecification.php index 3623f5c..f22e8b4 100644 --- a/test/Architecture/AuthorizationSpecification.php +++ b/test/Architecture/AuthorizationSpecification.php @@ -19,11 +19,10 @@ use PHPat\Test\PHPat; /** - * Architecture tests that enforce DDD and clean architecture principles. + * Architecture tests for the Authorization context. * * Domain is the innermost layer — it must not know about Application or Infrastructure. * Application sits between Domain and Infrastructure. - * Contract is a shared kernel that can be referenced by all layers. * Infrastructure implements Domain interfaces (Dependency Inversion). * * @internal @@ -32,50 +31,34 @@ final class AuthorizationSpecification { /** * Domain classes must not depend on Application or Infrastructure. - * Dependency on Contract (shared kernel) is permitted. */ public function testDomainDoesNotDependOnApplicationOrInfrastructure(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Authorization\Authorization\Domain')) + ->classes(Selector::inNamespace('Webify\User\Context\Authorization\Domain')) ->shouldNot() ->dependOn() ->classes( - Selector::inNamespace('Webify\User\Authorization\Application'), - Selector::inNamespace('Webify\User\Authorization\Infrastructure'), + Selector::inNamespace('Webify\User\Context\Authorization\Application'), + Selector::inNamespace('Webify\User\Context\Authorization\Infrastructure'), ) ->because('Domain is the innermost layer and must not depend on outer layers') ; } - /** - * Contract must not depend on Application or Infrastructure. - * It may reference Domain types. - */ - public function testContractDoesNotDependOnApplicationOrInfrastructure(): Rule - { - return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Authorization\Contract')) - ->shouldNot() - ->dependOn() - ->classes( - Selector::inNamespace('Webify\User\Authorization\Application'), - Selector::inNamespace('Webify\User\Authorization\Infrastructure'), - ) - ->because('Contract must not depend on outer layers') - ; - } - /** * Application classes must not depend on Infrastructure classes. + * + * NOTE: live today — `Authorization\Application\Query` and `Application\Service` are + * populated, so a violation here fails `composer analyse`. */ public function testApplicationDoesNotDependOnInfrastructure(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Authorization\Application')) + ->classes(Selector::inNamespace('Webify\User\Context\Authorization\Application')) ->shouldNot() ->dependOn() - ->classes(Selector::inNamespace('Webify\User\Authorization\Infrastructure')) + ->classes(Selector::inNamespace('Webify\User\Context\Authorization\Infrastructure')) ->because('Application should not depend on Infrastructure details') ; } @@ -86,7 +69,7 @@ public function testApplicationDoesNotDependOnInfrastructure(): Rule public function testDomainExceptionsExtendException(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Authorization\Domain\Exception')) + ->classes(Selector::inNamespace('Webify\User\Context\Authorization\Domain\Exception')) ->should() ->extend() ->classes(Selector::classname(Exception::class)) @@ -96,11 +79,16 @@ public function testDomainExceptionsExtendException(): Rule /** * All infrastructure exception classes must extend \Exception. + * + * NOTE: currently **inert** — `Authorization\Infrastructure` holds only `.gitkeep`, + * so this rule selects zero classes and passes vacuously. It guards nothing until the + * Authorization infrastructure layer lands. Identity and Authentication have real + * classes here and are genuinely enforced. */ public function testInfrastructureExceptionsExtendException(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Authorization\Infrastructure\Exception')) + ->classes(Selector::inNamespace('Webify\User\Context\Authorization\Infrastructure\Exception')) ->should() ->extend() ->classes(Selector::classname(Exception::class)) diff --git a/test/Architecture/DomainSpecification.php b/test/Architecture/DomainSpecification.php new file mode 100644 index 0000000..6b447fe --- /dev/null +++ b/test/Architecture/DomainSpecification.php @@ -0,0 +1,88 @@ + + */ +declare(strict_types=1); + +namespace Webify\User\Test\Architecture; + +use Exception; +use PHPat\Selector\Selector; +use PHPat\Test\Builder\Rule; +use PHPat\Test\PHPat; + +/** + * Architecture tests for the Domain in `src/Domain`. + * + * `src/Domain` holds the value objects and exceptions that Identity, Authentication and + * Authorization all depend on. Because it sits below every context, it must not reach back + * up into any of them — otherwise the dependency direction inverts and the contexts can no + * longer be developed or reasoned about independently. + * + * @internal + */ +final class DomainSpecification +{ + /** + * The shared kernel must not depend on a context. + */ + public function testSharedKernelDoesNotDependOnContext(): Rule + { + return PHPat::rule() + ->classes(Selector::inNamespace('Webify\User\Domain')) + ->shouldNot() + ->dependOn() + ->classes(Selector::inNamespace('Webify\User\Context')) + ->because('the shared kernel sits below every context and must not depend on one') + ; + } + + /** + * The shared kernel must not depend on the top-level application layer. + */ + public function testSharedKernelDoesNotDependOnApplication(): Rule + { + return PHPat::rule() + ->classes(Selector::inNamespace('Webify\User\Domain')) + ->shouldNot() + ->dependOn() + ->classes(Selector::inNamespace('Webify\User\Application')) + ->because('the shared kernel must not depend on an outer layer') + ; + } + + /** + * The shared kernel must not depend on the infrastructure layer. + */ + public function testSharedKernelDoesNotDependOnInfrastructure(): Rule + { + return PHPat::rule() + ->classes(Selector::inNamespace('Webify\User\Domain')) + ->shouldNot() + ->dependOn() + ->classes(Selector::inNamespace('Webify\User\Infrastructure')) + ->because('the shared kernel must not depend on an outer layer') + ; + } + + /** + * All shared kernel exception classes must extend \Exception. + */ + public function testSharedKernelExceptionsExtendException(): Rule + { + return PHPat::rule() + ->classes(Selector::inNamespace('Webify\User\Domain\Exception')) + ->should() + ->extend() + ->classes(Selector::classname(Exception::class)) + ->because('All domain exceptions must extend \Exception to ensure consistent error handling') + ; + } +} diff --git a/test/Architecture/IdentitySpecification.php b/test/Architecture/IdentitySpecification.php index 704e092..49900aa 100644 --- a/test/Architecture/IdentitySpecification.php +++ b/test/Architecture/IdentitySpecification.php @@ -19,11 +19,10 @@ use PHPat\Test\PHPat; /** - * Architecture tests that enforce DDD and clean architecture principles. + * Architecture tests for the Identity context. * * Domain is the innermost layer — it must not know about Application or Infrastructure. * Application sits between Domain and Infrastructure. - * Contract is a shared kernel that can be referenced by all layers. * Infrastructure implements Domain interfaces (Dependency Inversion). * * @internal @@ -32,50 +31,37 @@ final class IdentitySpecification { /** * Domain classes must not depend on Application or Infrastructure. - * Dependency on Contract (shared kernel) is permitted. + * + * Anything in `Identity\Domain` that orchestrates repositories, hashers, ID generators + * or event publishers is a use case and belongs in `Identity\Application` instead. */ public function testDomainDoesNotDependOnApplicationOrInfrastructure(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Identity\Identity\Domain')) + ->classes(Selector::inNamespace('Webify\User\Context\Identity\Domain')) ->shouldNot() ->dependOn() ->classes( - Selector::inNamespace('Webify\User\Identity\Application'), - Selector::inNamespace('Webify\User\Identity\Infrastructure'), + Selector::inNamespace('Webify\User\Context\Identity\Application'), + Selector::inNamespace('Webify\User\Context\Identity\Infrastructure'), ) ->because('Domain is the innermost layer and must not depend on outer layers') ; } - /** - * Contract must not depend on Application or Infrastructure. - * It may reference Domain types. - */ - public function testContractDoesNotDependOnApplicationOrInfrastructure(): Rule - { - return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Identity\Contract')) - ->shouldNot() - ->dependOn() - ->classes( - Selector::inNamespace('Webify\User\Identity\Application'), - Selector::inNamespace('Webify\User\Identity\Infrastructure'), - ) - ->because('Contract must not depend on outer layers') - ; - } - /** * Application classes must not depend on Infrastructure classes. + * + * NOTE: live today — `Identity\Application\Query` and `Identity\Application\Service` are + * populated, so a violation here fails `composer analyse`. */ public function testApplicationDoesNotDependOnInfrastructure(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Identity\Application')) + ->classes(Selector::inNamespace('Webify\User\Context\Identity\Application')) ->shouldNot() ->dependOn() - ->classes(Selector::inNamespace('Webify\User\Identity\Infrastructure')) + ->classes(Selector::inNamespace('Webify\User\Context\Identity\Infrastructure')) ->because('Application should not depend on Infrastructure details') ; } @@ -86,7 +72,7 @@ public function testApplicationDoesNotDependOnInfrastructure(): Rule public function testDomainExceptionsExtendException(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Identity\Domain\Exception')) + ->classes(Selector::inNamespace('Webify\User\Context\Identity\Domain\Exception')) ->should() ->extend() ->classes(Selector::classname(Exception::class)) @@ -100,7 +86,7 @@ public function testDomainExceptionsExtendException(): Rule public function testInfrastructureExceptionsExtendException(): Rule { return PHPat::rule() - ->classes(Selector::inNamespace('Webify\User\Identity\Infrastructure\Exception')) + ->classes(Selector::inNamespace('Webify\User\Context\Identity\Infrastructure\Exception')) ->should() ->extend() ->classes(Selector::classname(Exception::class)) diff --git a/test/Unit/Authentication/Domain/Service/UserStatusTranslatorTest.php b/test/Unit/Authentication/Domain/Service/UserStatusTranslatorTest.php deleted file mode 100644 index 30dae8c..0000000 --- a/test/Unit/Authentication/Domain/Service/UserStatusTranslatorTest.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ -declare(strict_types=1); - -namespace Webify\User\Test\Unit\Authentication\Domain\Service; - -use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; -use PHPUnit\Framework\TestCase; -use Webify\User\Authentication\Domain\Service\UserStatusTranslator; -use Webify\User\Authentication\Domain\ValueObject\UserStatus; - -/** - * UserStatusTranslatorTest tests the functionality of the UserStatusTranslator service. - * - * @internal - */ -#[CoversClass(UserStatusTranslator::class)] -#[CoversMethod(UserStatusTranslator::class, 'translate')] -final class UserStatusTranslatorTest extends TestCase -{ - private UserStatusTranslator $translator; - - protected function setUp(): void - { - $this->translator = new UserStatusTranslator(); - } - - #[Test] - public function testTranslateActive(): void - { - $this->assertTrue($this->translator->translate('active')->isActive()); - } - - #[Test] - public function testTranslateUnverified(): void - { - $result = $this->translator->translate('unverified'); - - $this->assertInstanceOf(UserStatus::class, $result); - $this->assertFalse($result->isActive()); - } - - #[Test] - public function testTranslateUnknownStatusDefaultsToUnverified(): void - { - $result = $this->translator->translate('unknown_status'); - - $this->assertInstanceOf(UserStatus::class, $result); - $this->assertFalse($result->isActive()); - } -} diff --git a/test/Unit/Authentication/Domain/Service/ChallengeBaseTest.php b/test/Unit/Context/Authentication/Application/Service/ChallengeBaseTest.php similarity index 93% rename from test/Unit/Authentication/Domain/Service/ChallengeBaseTest.php rename to test/Unit/Context/Authentication/Application/Service/ChallengeBaseTest.php index 1142326..a64cd25 100644 --- a/test/Unit/Authentication/Domain/Service/ChallengeBaseTest.php +++ b/test/Unit/Context/Authentication/Application/Service/ChallengeBaseTest.php @@ -11,31 +11,23 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authentication\Application\Service; use PHPUnit\Framework\Attributes\{AllowMockObjectsWithoutExpectations, CoversClass, CoversMethod, Test}; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Webify\Base\Domain\Contract\Authentication\{ - AuthenticatedUser as AuthenticatedUserDto, - CredentialsInterface, - StrategyInterface, - UserCredentials, - UserCredentialsLookupInterface -}; +use Webify\Base\Domain\Contract\Authentication\{AuthenticatedUser as AuthenticatedUserDto, CredentialsInterface, StrategyInterface, UserCredentials, UserCredentialsLookupInterface}; use Webify\Base\Domain\Contract\Authentication\Service\StrategyRegisterInterface; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Entity\Challenge; -use Webify\User\Authentication\Domain\Exception\{ - AuthenticationFailedException, - ChallengeNotFoundException -}; -use Webify\User\Authentication\Domain\Guard\UserMustBeActive; -use Webify\User\Authentication\Domain\Repository\{ChallengeRepositoryInterface, SessionRepositoryInterface}; -use Webify\User\Authentication\Domain\Service\{ChallengeBase, OpenSession, UserStatusTranslator, VerifyChallenge}; -use Webify\User\Authentication\Domain\ValueObject\{ChallengeCode, ChallengeId, ChallengeType, UserId}; +use Webify\User\Context\Authentication\Application\Service\{ChallengeBase, OpenSession, VerifyChallenge}; +use Webify\User\Context\Authentication\Domain\Entity\Challenge; +use Webify\User\Context\Authentication\Domain\Exception\{AuthenticationFailedException, ChallengeNotFoundException}; +use Webify\User\Context\Authentication\Domain\Guard\UserMustBeActive; +use Webify\User\Context\Authentication\Domain\Repository\{ChallengeRepositoryInterface, SessionRepositoryInterface}; +use Webify\User\Context\Authentication\Domain\ValueObject\{ChallengeCode, ChallengeId, ChallengeType}; +use Webify\User\Domain\ValueObject\UserId; use function in_array; @@ -116,7 +108,6 @@ protected function setUp(): void $this->userLookup, $this->strategyRegister, new UserMustBeActive(), - new UserStatusTranslator(), $verifyChallenge, $openSession ); diff --git a/test/Unit/Authentication/Domain/Service/IssueChallengeTest.php b/test/Unit/Context/Authentication/Application/Service/IssueChallengeTest.php similarity index 88% rename from test/Unit/Authentication/Domain/Service/IssueChallengeTest.php rename to test/Unit/Context/Authentication/Application/Service/IssueChallengeTest.php index d44dbf4..89c90f4 100644 --- a/test/Unit/Authentication/Domain/Service/IssueChallengeTest.php +++ b/test/Unit/Context/Authentication/Application/Service/IssueChallengeTest.php @@ -11,16 +11,17 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authentication\Application\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; -use Webify\User\Authentication\Domain\Entity\Challenge; -use Webify\User\Authentication\Domain\Repository\ChallengeRepositoryInterface; -use Webify\User\Authentication\Domain\Service\IssueChallenge; -use Webify\User\Authentication\Domain\ValueObject\{ChallengeType, UserId}; +use Webify\User\Context\Authentication\Application\Service\IssueChallenge; +use Webify\User\Context\Authentication\Domain\Entity\Challenge; +use Webify\User\Context\Authentication\Domain\Repository\ChallengeRepositoryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\ChallengeType; +use Webify\User\Domain\ValueObject\UserId; /** * Tests for the IssueChallenge domain service. diff --git a/test/Unit/Authentication/Domain/Service/OpenSessionTest.php b/test/Unit/Context/Authentication/Application/Service/OpenSessionTest.php similarity index 88% rename from test/Unit/Authentication/Domain/Service/OpenSessionTest.php rename to test/Unit/Context/Authentication/Application/Service/OpenSessionTest.php index e493995..36be9ca 100644 --- a/test/Unit/Authentication/Domain/Service/OpenSessionTest.php +++ b/test/Unit/Context/Authentication/Application/Service/OpenSessionTest.php @@ -11,17 +11,18 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authentication\Application\Service; use DateTimeImmutable; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; -use Webify\User\Authentication\Domain\Entity\Session; -use Webify\User\Authentication\Domain\Repository\SessionRepositoryInterface; -use Webify\User\Authentication\Domain\Service\OpenSession; -use Webify\User\Authentication\Domain\ValueObject\{AuthenticatedUser, UserId}; +use Webify\User\Context\Authentication\Application\Service\OpenSession; +use Webify\User\Context\Authentication\Domain\Entity\Session; +use Webify\User\Context\Authentication\Domain\Repository\SessionRepositoryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\AuthenticatedUser; +use Webify\User\Domain\ValueObject\UserId; /** * Tests for the OpenSession domain service. diff --git a/test/Unit/Authentication/Domain/Service/PasswordBaseTest.php b/test/Unit/Context/Authentication/Application/Service/PasswordBaseTest.php similarity index 92% rename from test/Unit/Authentication/Domain/Service/PasswordBaseTest.php rename to test/Unit/Context/Authentication/Application/Service/PasswordBaseTest.php index d2a561e..1c5b305 100644 --- a/test/Unit/Authentication/Domain/Service/PasswordBaseTest.php +++ b/test/Unit/Context/Authentication/Application/Service/PasswordBaseTest.php @@ -11,30 +11,22 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authentication\Application\Service; use PHPUnit\Framework\Attributes\{AllowMockObjectsWithoutExpectations, CoversClass, CoversMethod, Test}; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Webify\Base\Domain\Contract\Authentication\{AuthenticatedUser, - CredentialsInterface, - UserCredentials, - UserCredentialsLookupInterface}; +use Webify\Base\Domain\Contract\Authentication\{AuthenticatedUser, CredentialsInterface, UserCredentials, UserCredentialsLookupInterface}; use Webify\Base\Domain\Contract\Identity\Service\PasswordHasherInterface; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; -use Webify\User\Authentication\Domain\Entity\Challenge; -use Webify\User\Authentication\Domain\Exception\AuthenticationFailedException; -use Webify\User\Authentication\Domain\Guard\UserMustBeActive; -use Webify\User\Authentication\Domain\Repository\{ChallengeRepositoryInterface, SessionRepositoryInterface}; -use Webify\User\Authentication\Domain\Service\{ - ChallengeSecretDeliveryInterface, - IssueChallenge, - OpenSession, - PasswordBase, - UserStatusTranslator -}; -use Webify\User\Authentication\Domain\ValueObject\UserId; +use Webify\User\Context\Authentication\Application\Service\{IssueChallenge, OpenSession, PasswordBase}; +use Webify\User\Context\Authentication\Domain\Entity\Challenge; +use Webify\User\Context\Authentication\Domain\Exception\AuthenticationFailedException; +use Webify\User\Context\Authentication\Domain\Guard\UserMustBeActive; +use Webify\User\Context\Authentication\Domain\Repository\{ChallengeRepositoryInterface, SessionRepositoryInterface}; +use Webify\User\Context\Authentication\Domain\Service\ChallengeSecretDeliveryInterface; +use Webify\User\Domain\ValueObject\UserId; use function in_array; @@ -119,7 +111,6 @@ protected function setUp(): void $this->credentialLookup, $this->passwordHasher, new UserMustBeActive(), - new UserStatusTranslator(), $issueChallenge, $openSession, $this->delivery diff --git a/test/Unit/Authentication/Domain/Service/RefreshSessionTest.php b/test/Unit/Context/Authentication/Application/Service/RefreshSessionTest.php similarity index 87% rename from test/Unit/Authentication/Domain/Service/RefreshSessionTest.php rename to test/Unit/Context/Authentication/Application/Service/RefreshSessionTest.php index e87332a..4c5e5fd 100644 --- a/test/Unit/Authentication/Domain/Service/RefreshSessionTest.php +++ b/test/Unit/Context/Authentication/Application/Service/RefreshSessionTest.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authentication\Application\Service; use DateTimeImmutable; use PHPUnit\Framework\Attributes\{AllowMockObjectsWithoutExpectations, CoversClass, CoversMethod, Test}; @@ -19,11 +19,12 @@ use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Entity\Session; -use Webify\User\Authentication\Domain\Exception\{CannotRefreshSessionException, SessionNotFoundException}; -use Webify\User\Authentication\Domain\Repository\SessionRepositoryInterface; -use Webify\User\Authentication\Domain\Service\RefreshSession; -use Webify\User\Authentication\Domain\ValueObject\{AccessToken, RefreshToken, SessionId, UserId}; +use Webify\User\Context\Authentication\Application\Service\RefreshSession; +use Webify\User\Context\Authentication\Domain\Entity\Session; +use Webify\User\Context\Authentication\Domain\Exception\{CannotRefreshSessionException, SessionNotFoundException}; +use Webify\User\Context\Authentication\Domain\Repository\SessionRepositoryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\{AccessToken, RefreshToken, SessionId}; +use Webify\User\Domain\ValueObject\UserId; /** * Tests for the RefreshSession domain service. diff --git a/test/Unit/Authentication/Domain/Service/RevokeSessionTest.php b/test/Unit/Context/Authentication/Application/Service/RevokeSessionTest.php similarity index 86% rename from test/Unit/Authentication/Domain/Service/RevokeSessionTest.php rename to test/Unit/Context/Authentication/Application/Service/RevokeSessionTest.php index 25f2a06..9472aad 100644 --- a/test/Unit/Authentication/Domain/Service/RevokeSessionTest.php +++ b/test/Unit/Context/Authentication/Application/Service/RevokeSessionTest.php @@ -11,17 +11,18 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authentication\Application\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Entity\Session; -use Webify\User\Authentication\Domain\Exception\SessionNotFoundException; -use Webify\User\Authentication\Domain\Repository\SessionRepositoryInterface; -use Webify\User\Authentication\Domain\Service\RevokeSession; -use Webify\User\Authentication\Domain\ValueObject\{AccessToken, RefreshToken, SessionId, UserId}; +use Webify\User\Context\Authentication\Application\Service\RevokeSession; +use Webify\User\Context\Authentication\Domain\Entity\Session; +use Webify\User\Context\Authentication\Domain\Exception\SessionNotFoundException; +use Webify\User\Context\Authentication\Domain\Repository\SessionRepositoryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\{AccessToken, RefreshToken, SessionId}; +use Webify\User\Domain\ValueObject\UserId; /** * Tests for the RevokeSession service. diff --git a/test/Unit/Authentication/Domain/Service/VerifyChallengeTest.php b/test/Unit/Context/Authentication/Application/Service/VerifyChallengeTest.php similarity index 89% rename from test/Unit/Authentication/Domain/Service/VerifyChallengeTest.php rename to test/Unit/Context/Authentication/Application/Service/VerifyChallengeTest.php index ac80a73..a8499e9 100644 --- a/test/Unit/Authentication/Domain/Service/VerifyChallengeTest.php +++ b/test/Unit/Context/Authentication/Application/Service/VerifyChallengeTest.php @@ -11,23 +11,18 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authentication\Application\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Entity\Challenge; -use Webify\User\Authentication\Domain\Exception\{ChallengeNotFoundException, InvalidChallengeSecretException}; -use Webify\User\Authentication\Domain\Repository\ChallengeRepositoryInterface; -use Webify\User\Authentication\Domain\Service\VerifyChallenge; -use Webify\User\Authentication\Domain\ValueObject\{ - ChallengeCode, - ChallengeId, - ChallengeToken, - ChallengeType, - UserId -}; +use Webify\User\Context\Authentication\Application\Service\VerifyChallenge; +use Webify\User\Context\Authentication\Domain\Entity\Challenge; +use Webify\User\Context\Authentication\Domain\Exception\{ChallengeNotFoundException, InvalidChallengeSecretException}; +use Webify\User\Context\Authentication\Domain\Repository\ChallengeRepositoryInterface; +use Webify\User\Context\Authentication\Domain\ValueObject\{ChallengeCode, ChallengeId, ChallengeToken, ChallengeType}; +use Webify\User\Domain\ValueObject\UserId; /** * Tests for the VerifyChallenge domain service. diff --git a/test/Unit/Authentication/Domain/Strategy/ChallengeCodeStrategyTest.php b/test/Unit/Context/Authentication/Application/Strategy/ChallengeCodeStrategyTest.php similarity index 89% rename from test/Unit/Authentication/Domain/Strategy/ChallengeCodeStrategyTest.php rename to test/Unit/Context/Authentication/Application/Strategy/ChallengeCodeStrategyTest.php index c622977..7b1ecd9 100644 --- a/test/Unit/Authentication/Domain/Strategy/ChallengeCodeStrategyTest.php +++ b/test/Unit/Context/Authentication/Application/Strategy/ChallengeCodeStrategyTest.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Strategy; +namespace Webify\User\Test\Unit\Context\Authentication\Application\Strategy; use PHPUnit\Framework\Attributes\{AllowMockObjectsWithoutExpectations, CoversClass, CoversMethod, Test}; use PHPUnit\Framework\MockObject\MockObject; @@ -19,11 +19,12 @@ use Webify\Base\Domain\Contract\Authentication\{CredentialsInterface, UserCredentials}; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; -use Webify\User\Authentication\Domain\Entity\Challenge; -use Webify\User\Authentication\Domain\Repository\ChallengeRepositoryInterface; -use Webify\User\Authentication\Domain\Service\{ChallengeSecretDeliveryInterface, IssueChallenge}; -use Webify\User\Authentication\Domain\Strategy\ChallengeCodeStrategy; -use Webify\User\Authentication\Domain\ValueObject\UserId; +use Webify\User\Context\Authentication\Application\Service\IssueChallenge; +use Webify\User\Context\Authentication\Application\Strategy\ChallengeCodeStrategy; +use Webify\User\Context\Authentication\Domain\Entity\Challenge; +use Webify\User\Context\Authentication\Domain\Repository\ChallengeRepositoryInterface; +use Webify\User\Context\Authentication\Domain\Service\ChallengeSecretDeliveryInterface; +use Webify\User\Domain\ValueObject\UserId; /** * Tests for the ChallengeCodeStrategy. diff --git a/test/Unit/Authentication/Domain/Strategy/ChallengeTokenStrategyTest.php b/test/Unit/Context/Authentication/Application/Strategy/ChallengeTokenStrategyTest.php similarity index 89% rename from test/Unit/Authentication/Domain/Strategy/ChallengeTokenStrategyTest.php rename to test/Unit/Context/Authentication/Application/Strategy/ChallengeTokenStrategyTest.php index 1c4c949..a68ed51 100644 --- a/test/Unit/Authentication/Domain/Strategy/ChallengeTokenStrategyTest.php +++ b/test/Unit/Context/Authentication/Application/Strategy/ChallengeTokenStrategyTest.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Strategy; +namespace Webify\User\Test\Unit\Context\Authentication\Application\Strategy; use PHPUnit\Framework\Attributes\{AllowMockObjectsWithoutExpectations, CoversClass, CoversMethod, Test}; use PHPUnit\Framework\MockObject\MockObject; @@ -19,11 +19,12 @@ use Webify\Base\Domain\Contract\Authentication\{CredentialsInterface, UserCredentials}; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; -use Webify\User\Authentication\Domain\Entity\Challenge; -use Webify\User\Authentication\Domain\Repository\ChallengeRepositoryInterface; -use Webify\User\Authentication\Domain\Service\{ChallengeSecretDeliveryInterface, IssueChallenge}; -use Webify\User\Authentication\Domain\Strategy\ChallengeTokenStrategy; -use Webify\User\Authentication\Domain\ValueObject\UserId; +use Webify\User\Context\Authentication\Application\Service\IssueChallenge; +use Webify\User\Context\Authentication\Application\Strategy\ChallengeTokenStrategy; +use Webify\User\Context\Authentication\Domain\Entity\Challenge; +use Webify\User\Context\Authentication\Domain\Repository\ChallengeRepositoryInterface; +use Webify\User\Context\Authentication\Domain\Service\ChallengeSecretDeliveryInterface; +use Webify\User\Domain\ValueObject\UserId; /** * Tests for the ChallengeTokenStrategy. diff --git a/test/Unit/Authentication/Domain/Entity/ChallengeTest.php b/test/Unit/Context/Authentication/Domain/Entity/ChallengeTest.php similarity index 93% rename from test/Unit/Authentication/Domain/Entity/ChallengeTest.php rename to test/Unit/Context/Authentication/Domain/Entity/ChallengeTest.php index 754fe9e..d4fef11 100644 --- a/test/Unit/Authentication/Domain/Entity/ChallengeTest.php +++ b/test/Unit/Context/Authentication/Domain/Entity/ChallengeTest.php @@ -11,22 +11,16 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Entity; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\Entity; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Entity\Challenge; -use Webify\User\Authentication\Domain\Event\{ChallengeFailed, ChallengeVerified}; -use Webify\User\Authentication\Domain\Exception\{ChallengeVerificationFailedException, InvalidChallengeSecretException}; -use Webify\User\Authentication\Domain\ValueObject\{ - ChallengeCode, - ChallengeId, - ChallengeStatus, - ChallengeToken, - ChallengeType, - UserId -}; +use Webify\User\Context\Authentication\Domain\Entity\Challenge; +use Webify\User\Context\Authentication\Domain\Event\{ChallengeFailed, ChallengeVerified}; +use Webify\User\Context\Authentication\Domain\Exception\{ChallengeVerificationFailedException, InvalidChallengeSecretException}; +use Webify\User\Context\Authentication\Domain\ValueObject\{ChallengeCode, ChallengeId, ChallengeStatus, ChallengeToken, ChallengeType}; +use Webify\User\Domain\ValueObject\UserId; /** * Tests for the Challenge entity. diff --git a/test/Unit/Authentication/Domain/Entity/SessionTest.php b/test/Unit/Context/Authentication/Domain/Entity/SessionTest.php similarity index 92% rename from test/Unit/Authentication/Domain/Entity/SessionTest.php rename to test/Unit/Context/Authentication/Domain/Entity/SessionTest.php index b428a07..20d37a1 100644 --- a/test/Unit/Authentication/Domain/Entity/SessionTest.php +++ b/test/Unit/Context/Authentication/Domain/Entity/SessionTest.php @@ -11,15 +11,16 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Entity; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\Entity; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authentication\Domain\Entity\Session; -use Webify\User\Authentication\Domain\Event\{SessionWasOpened, SessionWasRefreshed, SessionWasRevoked}; -use Webify\User\Authentication\Domain\Exception\CannotRefreshSessionException; -use Webify\User\Authentication\Domain\ValueObject\{AccessToken, RefreshToken, SessionId, UserId}; +use Webify\User\Context\Authentication\Domain\Entity\Session; +use Webify\User\Context\Authentication\Domain\Event\{SessionWasOpened, SessionWasRefreshed, SessionWasRevoked}; +use Webify\User\Context\Authentication\Domain\Exception\CannotRefreshSessionException; +use Webify\User\Context\Authentication\Domain\ValueObject\{AccessToken, RefreshToken, SessionId}; +use Webify\User\Domain\ValueObject\UserId; /** * Tests for the Session entity. diff --git a/test/Unit/Authentication/Domain/Guard/UserMustBeActiveTest.php b/test/Unit/Context/Authentication/Domain/Guard/UserMustBeActiveTest.php similarity index 81% rename from test/Unit/Authentication/Domain/Guard/UserMustBeActiveTest.php rename to test/Unit/Context/Authentication/Domain/Guard/UserMustBeActiveTest.php index 6c65b11..f191c27 100644 --- a/test/Unit/Authentication/Domain/Guard/UserMustBeActiveTest.php +++ b/test/Unit/Context/Authentication/Domain/Guard/UserMustBeActiveTest.php @@ -11,13 +11,13 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\Guard; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\Guard; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authentication\Domain\Exception\AuthenticationFailedException; -use Webify\User\Authentication\Domain\Guard\UserMustBeActive; -use Webify\User\Authentication\Domain\ValueObject\UserStatus; +use Webify\User\Context\Authentication\Domain\Exception\AuthenticationFailedException; +use Webify\User\Context\Authentication\Domain\Guard\UserMustBeActive; +use Webify\User\Domain\ValueObject\UserStatus; /** * Tests for the UserMustBeActive guard. diff --git a/test/Unit/Authentication/Domain/ValueObject/AccessTokenTest.php b/test/Unit/Context/Authentication/Domain/ValueObject/AccessTokenTest.php similarity index 93% rename from test/Unit/Authentication/Domain/ValueObject/AccessTokenTest.php rename to test/Unit/Context/Authentication/Domain/ValueObject/AccessTokenTest.php index 6ad3441..c5fa89c 100644 --- a/test/Unit/Authentication/Domain/ValueObject/AccessTokenTest.php +++ b/test/Unit/Context/Authentication/Domain/ValueObject/AccessTokenTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authentication\Domain\Exception\InvalidAccessTokenException; -use Webify\User\Authentication\Domain\ValueObject\AccessToken; +use Webify\User\Context\Authentication\Domain\Exception\InvalidAccessTokenException; +use Webify\User\Context\Authentication\Domain\ValueObject\AccessToken; /** * Tests for the AccessToken value object. diff --git a/test/Unit/Authentication/Domain/ValueObject/ChallengeCodeTest.php b/test/Unit/Context/Authentication/Domain/ValueObject/ChallengeCodeTest.php similarity index 93% rename from test/Unit/Authentication/Domain/ValueObject/ChallengeCodeTest.php rename to test/Unit/Context/Authentication/Domain/ValueObject/ChallengeCodeTest.php index 73434b7..d96cc0e 100644 --- a/test/Unit/Authentication/Domain/ValueObject/ChallengeCodeTest.php +++ b/test/Unit/Context/Authentication/Domain/ValueObject/ChallengeCodeTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authentication\Domain\Exception\InvalidChallengeCodeException; -use Webify\User\Authentication\Domain\ValueObject\ChallengeCode; +use Webify\User\Context\Authentication\Domain\Exception\InvalidChallengeCodeException; +use Webify\User\Context\Authentication\Domain\ValueObject\ChallengeCode; /** * Tests for the ChallengeCode value object. diff --git a/test/Unit/Authentication/Domain/ValueObject/ChallengeIdTest.php b/test/Unit/Context/Authentication/Domain/ValueObject/ChallengeIdTest.php similarity index 85% rename from test/Unit/Authentication/Domain/ValueObject/ChallengeIdTest.php rename to test/Unit/Context/Authentication/Domain/ValueObject/ChallengeIdTest.php index b1a06c7..bcf09cd 100644 --- a/test/Unit/Authentication/Domain/ValueObject/ChallengeIdTest.php +++ b/test/Unit/Context/Authentication/Domain/ValueObject/ChallengeIdTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authentication\Domain\Exception\InvalidChallengeIdException; -use Webify\User\Authentication\Domain\ValueObject\ChallengeId; +use Webify\User\Context\Authentication\Domain\Exception\InvalidChallengeIdException; +use Webify\User\Context\Authentication\Domain\ValueObject\ChallengeId; /** * Tests for the ChallengeId value object. diff --git a/test/Unit/Authentication/Domain/ValueObject/ChallengeStatusTest.php b/test/Unit/Context/Authentication/Domain/ValueObject/ChallengeStatusTest.php similarity index 93% rename from test/Unit/Authentication/Domain/ValueObject/ChallengeStatusTest.php rename to test/Unit/Context/Authentication/Domain/ValueObject/ChallengeStatusTest.php index 16d17db..c1c32c4 100644 --- a/test/Unit/Authentication/Domain/ValueObject/ChallengeStatusTest.php +++ b/test/Unit/Context/Authentication/Domain/ValueObject/ChallengeStatusTest.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authentication\Domain\ValueObject\ChallengeStatus; +use Webify\User\Context\Authentication\Domain\ValueObject\ChallengeStatus; /** * Tests for the ChallengeStatus enum. diff --git a/test/Unit/Authentication/Domain/ValueObject/ChallengeTokenTest.php b/test/Unit/Context/Authentication/Domain/ValueObject/ChallengeTokenTest.php similarity index 93% rename from test/Unit/Authentication/Domain/ValueObject/ChallengeTokenTest.php rename to test/Unit/Context/Authentication/Domain/ValueObject/ChallengeTokenTest.php index 48dd044..47e68fc 100644 --- a/test/Unit/Authentication/Domain/ValueObject/ChallengeTokenTest.php +++ b/test/Unit/Context/Authentication/Domain/ValueObject/ChallengeTokenTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authentication\Domain\Exception\InvalidChallengeTokenException; -use Webify\User\Authentication\Domain\ValueObject\ChallengeToken; +use Webify\User\Context\Authentication\Domain\Exception\InvalidChallengeTokenException; +use Webify\User\Context\Authentication\Domain\ValueObject\ChallengeToken; /** * Tests for the ChallengeToken value object. diff --git a/test/Unit/Authentication/Domain/ValueObject/ChallengeTypeTest.php b/test/Unit/Context/Authentication/Domain/ValueObject/ChallengeTypeTest.php similarity index 93% rename from test/Unit/Authentication/Domain/ValueObject/ChallengeTypeTest.php rename to test/Unit/Context/Authentication/Domain/ValueObject/ChallengeTypeTest.php index 49653ea..8f13d83 100644 --- a/test/Unit/Authentication/Domain/ValueObject/ChallengeTypeTest.php +++ b/test/Unit/Context/Authentication/Domain/ValueObject/ChallengeTypeTest.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authentication\Domain\ValueObject\ChallengeType; +use Webify\User\Context\Authentication\Domain\ValueObject\ChallengeType; /** * ChallengeTypeTest tests the functionality of the ChallengeType enum. diff --git a/test/Unit/Authentication/Domain/ValueObject/RefreshTokenTest.php b/test/Unit/Context/Authentication/Domain/ValueObject/RefreshTokenTest.php similarity index 93% rename from test/Unit/Authentication/Domain/ValueObject/RefreshTokenTest.php rename to test/Unit/Context/Authentication/Domain/ValueObject/RefreshTokenTest.php index 177fb6f..aa2ff99 100644 --- a/test/Unit/Authentication/Domain/ValueObject/RefreshTokenTest.php +++ b/test/Unit/Context/Authentication/Domain/ValueObject/RefreshTokenTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authentication\Domain\Exception\InvalidRefreshTokenException; -use Webify\User\Authentication\Domain\ValueObject\RefreshToken; +use Webify\User\Context\Authentication\Domain\Exception\InvalidRefreshTokenException; +use Webify\User\Context\Authentication\Domain\ValueObject\RefreshToken; /** * Tests for the RefreshToken value object. diff --git a/test/Unit/Authentication/Domain/ValueObject/SessionIdTest.php b/test/Unit/Context/Authentication/Domain/ValueObject/SessionIdTest.php similarity index 84% rename from test/Unit/Authentication/Domain/ValueObject/SessionIdTest.php rename to test/Unit/Context/Authentication/Domain/ValueObject/SessionIdTest.php index b8dc704..4ed3e86 100644 --- a/test/Unit/Authentication/Domain/ValueObject/SessionIdTest.php +++ b/test/Unit/Context/Authentication/Domain/ValueObject/SessionIdTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authentication\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authentication\Domain\Exception\InvalidSessionIdException; -use Webify\User\Authentication\Domain\ValueObject\SessionId; +use Webify\User\Context\Authentication\Domain\Exception\InvalidSessionIdException; +use Webify\User\Context\Authentication\Domain\ValueObject\SessionId; /** * Tests for the TokenId value object. diff --git a/test/Unit/Authentication/Infrastructure/Service/StrategyRegisterTest.php b/test/Unit/Context/Authentication/Infrastructure/Service/StrategyRegisterTest.php similarity index 92% rename from test/Unit/Authentication/Infrastructure/Service/StrategyRegisterTest.php rename to test/Unit/Context/Authentication/Infrastructure/Service/StrategyRegisterTest.php index d7ed0fc..84c3b70 100644 --- a/test/Unit/Authentication/Infrastructure/Service/StrategyRegisterTest.php +++ b/test/Unit/Context/Authentication/Infrastructure/Service/StrategyRegisterTest.php @@ -11,13 +11,13 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authentication\Infrastructure\Service; +namespace Webify\User\Test\Unit\Context\Authentication\Infrastructure\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Contract\Authentication\StrategyInterface; -use Webify\User\Authentication\Infrastructure\Exception\StrategyNotFoundException; -use Webify\User\Authentication\Infrastructure\Service\StrategyRegister; +use Webify\User\Context\Authentication\Infrastructure\Exception\StrategyNotFoundException; +use Webify\User\Context\Authentication\Infrastructure\Service\StrategyRegister; /** * Tests for the StrategyRegister. diff --git a/test/Unit/Authorization/Domain/Service/AssignRoleTest.php b/test/Unit/Context/Authorization/Application/Service/AssignRoleTest.php similarity index 91% rename from test/Unit/Authorization/Domain/Service/AssignRoleTest.php rename to test/Unit/Context/Authorization/Application/Service/AssignRoleTest.php index 4fdeb96..6939438 100644 --- a/test/Unit/Authorization/Domain/Service/AssignRoleTest.php +++ b/test/Unit/Context/Authorization/Application/Service/AssignRoleTest.php @@ -11,20 +11,20 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authorization\Application\Service; use DateTimeImmutable; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; -use Webify\User\Authorization\Domain\Collection\PermissionCollection; -use Webify\User\Authorization\Domain\Entity\Role; -use Webify\User\Authorization\Domain\Exception\DuplicateRoleAssignmentException; -use Webify\User\Authorization\Domain\Guard\DuplicateRoleAssignment; -use Webify\User\Authorization\Domain\Repository\{RoleAssignmentRepositoryInterface, RoleRepositoryInterface}; -use Webify\User\Authorization\Domain\Service\AssignRole; -use Webify\User\Authorization\Domain\ValueObject\{RoleId, RoleName, RoleSlug, SubjectId, TenantId}; +use Webify\User\Context\Authorization\Application\Service\AssignRole; +use Webify\User\Context\Authorization\Domain\Collection\PermissionCollection; +use Webify\User\Context\Authorization\Domain\Entity\Role; +use Webify\User\Context\Authorization\Domain\Exception\DuplicateRoleAssignmentException; +use Webify\User\Context\Authorization\Domain\Guard\DuplicateRoleAssignment; +use Webify\User\Context\Authorization\Domain\Repository\{RoleAssignmentRepositoryInterface, RoleRepositoryInterface}; +use Webify\User\Context\Authorization\Domain\ValueObject\{RoleId, RoleName, RoleSlug, SubjectId, TenantId}; /** * RoleAssignTest tests the functionality of the RoleAssign service. diff --git a/test/Unit/Authorization/Domain/Service/CheckAccessTest.php b/test/Unit/Context/Authorization/Application/Service/CheckAccessTest.php similarity index 95% rename from test/Unit/Authorization/Domain/Service/CheckAccessTest.php rename to test/Unit/Context/Authorization/Application/Service/CheckAccessTest.php index a18a4e7..7f910e5 100644 --- a/test/Unit/Authorization/Domain/Service/CheckAccessTest.php +++ b/test/Unit/Context/Authorization/Application/Service/CheckAccessTest.php @@ -11,18 +11,19 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authorization\Application\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Contract\Authorization\{AuthorizableResourceInterface, AuthorizableSubjectInterface}; use Webify\Base\Domain\Contract\Authorization\Service\RuleRegistryInterface; use Webify\Base\Domain\Exception\AccessDeniedException; -use Webify\User\Authorization\Domain\Collection\{PermissionCollection, RoleAssignmentCollection}; -use Webify\User\Authorization\Domain\Entity\{Role, RoleAssignment}; -use Webify\User\Authorization\Domain\Repository\{RoleAssignmentRepositoryInterface, RoleRepositoryInterface}; -use Webify\User\Authorization\Domain\Service\{Authorization, CheckAccess}; -use Webify\User\Authorization\Domain\ValueObject\{Permission, RoleAssignmentId, RoleId, RoleName, RoleSlug, SubjectId}; +use Webify\User\Context\Authorization\Application\Service\CheckAccess; +use Webify\User\Context\Authorization\Domain\Collection\{PermissionCollection, RoleAssignmentCollection}; +use Webify\User\Context\Authorization\Domain\Entity\{Role, RoleAssignment}; +use Webify\User\Context\Authorization\Domain\Repository\{RoleAssignmentRepositoryInterface, RoleRepositoryInterface}; +use Webify\User\Context\Authorization\Domain\Service\Authorization; +use Webify\User\Context\Authorization\Domain\ValueObject\{Permission, RoleAssignmentId, RoleId, RoleName, RoleSlug, SubjectId}; /** * CheckAccessTest tests the functionality of the CheckAccess service. diff --git a/test/Unit/Authorization/Domain/Service/CreateRoleTest.php b/test/Unit/Context/Authorization/Application/Service/CreateRoleTest.php similarity index 93% rename from test/Unit/Authorization/Domain/Service/CreateRoleTest.php rename to test/Unit/Context/Authorization/Application/Service/CreateRoleTest.php index 04bcac4..a233507 100644 --- a/test/Unit/Authorization/Domain/Service/CreateRoleTest.php +++ b/test/Unit/Context/Authorization/Application/Service/CreateRoleTest.php @@ -11,18 +11,18 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authorization\Application\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\{SlugifyInterface, UlidGeneratorInterface}; -use Webify\User\Authorization\Domain\Entity\Role; -use Webify\User\Authorization\Domain\Exception\RoleAlreadyExistsException; -use Webify\User\Authorization\Domain\Guard\RoleAlreadyExists; -use Webify\User\Authorization\Domain\Repository\RoleRepositoryInterface; -use Webify\User\Authorization\Domain\Service\CreateRole; -use Webify\User\Authorization\Domain\ValueObject\{RoleName, RoleSlug}; +use Webify\User\Context\Authorization\Application\Service\CreateRole; +use Webify\User\Context\Authorization\Domain\Entity\Role; +use Webify\User\Context\Authorization\Domain\Exception\RoleAlreadyExistsException; +use Webify\User\Context\Authorization\Domain\Guard\RoleAlreadyExists; +use Webify\User\Context\Authorization\Domain\Repository\RoleRepositoryInterface; +use Webify\User\Context\Authorization\Domain\ValueObject\{RoleName, RoleSlug}; /** * CreateRoleTest tests the functionality of the CreateRole service. diff --git a/test/Unit/Authorization/Domain/Service/RevokeRoleTest.php b/test/Unit/Context/Authorization/Application/Service/RevokeRoleTest.php similarity index 89% rename from test/Unit/Authorization/Domain/Service/RevokeRoleTest.php rename to test/Unit/Context/Authorization/Application/Service/RevokeRoleTest.php index e5ad907..1f61a90 100644 --- a/test/Unit/Authorization/Domain/Service/RevokeRoleTest.php +++ b/test/Unit/Context/Authorization/Application/Service/RevokeRoleTest.php @@ -11,18 +11,18 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authorization\Application\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authorization\Domain\Entity\RoleAssignment; -use Webify\User\Authorization\Domain\Event\RoleRevoked; -use Webify\User\Authorization\Domain\Exception\RoleAssignmentNotFoundException; -use Webify\User\Authorization\Domain\Repository\RoleAssignmentRepositoryInterface; -use Webify\User\Authorization\Domain\Service\RevokeRole; -use Webify\User\Authorization\Domain\ValueObject\{RoleAssignmentId, RoleId, SubjectId, TenantId}; +use Webify\User\Context\Authorization\Application\Service\RevokeRole; +use Webify\User\Context\Authorization\Domain\Entity\RoleAssignment; +use Webify\User\Context\Authorization\Domain\Event\RoleRevoked; +use Webify\User\Context\Authorization\Domain\Exception\RoleAssignmentNotFoundException; +use Webify\User\Context\Authorization\Domain\Repository\RoleAssignmentRepositoryInterface; +use Webify\User\Context\Authorization\Domain\ValueObject\{RoleAssignmentId, RoleId, SubjectId, TenantId}; /** * RevokeRoleTest tests the functionality of the RevokeRole service. diff --git a/test/Unit/Authorization/Domain/Entity/RoleAssignmentTest.php b/test/Unit/Context/Authorization/Domain/Entity/RoleAssignmentTest.php similarity index 95% rename from test/Unit/Authorization/Domain/Entity/RoleAssignmentTest.php rename to test/Unit/Context/Authorization/Domain/Entity/RoleAssignmentTest.php index 59b4f1a..d87fd35 100644 --- a/test/Unit/Authorization/Domain/Entity/RoleAssignmentTest.php +++ b/test/Unit/Context/Authorization/Domain/Entity/RoleAssignmentTest.php @@ -11,14 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\Entity; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\Entity; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authorization\Domain\Entity\RoleAssignment; -use Webify\User\Authorization\Domain\Event\RoleAssigned; -use Webify\User\Authorization\Domain\ValueObject\{RoleAssignmentId, RoleId, SubjectId, TenantId}; +use Webify\User\Context\Authorization\Domain\Entity\RoleAssignment; +use Webify\User\Context\Authorization\Domain\Event\RoleAssigned; +use Webify\User\Context\Authorization\Domain\ValueObject\{RoleAssignmentId, RoleId, SubjectId, TenantId}; /** * RoleAssignmentTest tests the functionality of the RoleAssignment aggregate root. diff --git a/test/Unit/Authorization/Domain/Entity/RoleTest.php b/test/Unit/Context/Authorization/Domain/Entity/RoleTest.php similarity index 92% rename from test/Unit/Authorization/Domain/Entity/RoleTest.php rename to test/Unit/Context/Authorization/Domain/Entity/RoleTest.php index ab38583..ff6cf74 100644 --- a/test/Unit/Authorization/Domain/Entity/RoleTest.php +++ b/test/Unit/Context/Authorization/Domain/Entity/RoleTest.php @@ -11,14 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\Entity; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\Entity; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authorization\Domain\Collection\PermissionCollection; -use Webify\User\Authorization\Domain\Entity\Role; -use Webify\User\Authorization\Domain\Event\{PermissionGranted, PermissionRevoked, RoleCreated}; -use Webify\User\Authorization\Domain\ValueObject\{Permission, RoleId, RoleName, RoleSlug}; +use Webify\User\Context\Authorization\Domain\Collection\PermissionCollection; +use Webify\User\Context\Authorization\Domain\Entity\Role; +use Webify\User\Context\Authorization\Domain\Event\{PermissionGranted, PermissionRevoked, RoleCreated}; +use Webify\User\Context\Authorization\Domain\ValueObject\{Permission, RoleId, RoleName, RoleSlug}; /** * RoleTest tests the functionality of the Role entity. diff --git a/test/Unit/Authorization/Domain/Guard/DuplicateRoleAssignmentTest.php b/test/Unit/Context/Authorization/Domain/Guard/DuplicateRoleAssignmentTest.php similarity index 82% rename from test/Unit/Authorization/Domain/Guard/DuplicateRoleAssignmentTest.php rename to test/Unit/Context/Authorization/Domain/Guard/DuplicateRoleAssignmentTest.php index c636d0c..2848037 100644 --- a/test/Unit/Authorization/Domain/Guard/DuplicateRoleAssignmentTest.php +++ b/test/Unit/Context/Authorization/Domain/Guard/DuplicateRoleAssignmentTest.php @@ -11,14 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\Guard; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\Guard; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authorization\Domain\Exception\DuplicateRoleAssignmentException; -use Webify\User\Authorization\Domain\Guard\DuplicateRoleAssignment; -use Webify\User\Authorization\Domain\Repository\RoleAssignmentRepositoryInterface; -use Webify\User\Authorization\Domain\ValueObject\{RoleId, SubjectId}; +use Webify\User\Context\Authorization\Domain\Exception\DuplicateRoleAssignmentException; +use Webify\User\Context\Authorization\Domain\Guard\DuplicateRoleAssignment; +use Webify\User\Context\Authorization\Domain\Repository\RoleAssignmentRepositoryInterface; +use Webify\User\Context\Authorization\Domain\ValueObject\{RoleId, SubjectId}; /** * DuplicateRoleAssignmentTest tests the functionality of the DuplicateRoleAssignment guard. diff --git a/test/Unit/Authorization/Domain/Guard/RoleAlreadyExistsTest.php b/test/Unit/Context/Authorization/Domain/Guard/RoleAlreadyExistsTest.php similarity index 82% rename from test/Unit/Authorization/Domain/Guard/RoleAlreadyExistsTest.php rename to test/Unit/Context/Authorization/Domain/Guard/RoleAlreadyExistsTest.php index d92329e..b7bbdf1 100644 --- a/test/Unit/Authorization/Domain/Guard/RoleAlreadyExistsTest.php +++ b/test/Unit/Context/Authorization/Domain/Guard/RoleAlreadyExistsTest.php @@ -11,14 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\Guard; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\Guard; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authorization\Domain\Exception\RoleAlreadyExistsException; -use Webify\User\Authorization\Domain\Guard\RoleAlreadyExists; -use Webify\User\Authorization\Domain\Repository\RoleRepositoryInterface; -use Webify\User\Authorization\Domain\ValueObject\RoleSlug; +use Webify\User\Context\Authorization\Domain\Exception\RoleAlreadyExistsException; +use Webify\User\Context\Authorization\Domain\Guard\RoleAlreadyExists; +use Webify\User\Context\Authorization\Domain\Repository\RoleRepositoryInterface; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleSlug; /** * RoleAlreadyExistsTest tests the functionality of the RoleAlreadyExists guard. diff --git a/test/Unit/Authorization/Domain/Service/AuthorizationTest.php b/test/Unit/Context/Authorization/Domain/Service/AuthorizationTest.php similarity index 97% rename from test/Unit/Authorization/Domain/Service/AuthorizationTest.php rename to test/Unit/Context/Authorization/Domain/Service/AuthorizationTest.php index 9f1bd92..3b2b421 100644 --- a/test/Unit/Authorization/Domain/Service/AuthorizationTest.php +++ b/test/Unit/Context/Authorization/Domain/Service/AuthorizationTest.php @@ -11,27 +11,19 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\Service; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\Base\Domain\Contract\Authorization\{AuthorizableResourceInterface, - AuthorizableSubjectInterface, - RuleInterface}; +use Webify\Base\Domain\Contract\Authorization\{AuthorizableResourceInterface, AuthorizableSubjectInterface, RuleInterface}; use Webify\Base\Domain\Contract\Authorization\Service\RuleRegistryInterface; use Webify\Base\Domain\ValueObject\DateTime; -use Webify\User\Authorization\Domain\Collection\{PermissionCollection, RoleAssignmentCollection}; -use Webify\User\Authorization\Domain\Entity\{Role, RoleAssignment}; -use Webify\User\Authorization\Domain\Exception\RoleNotFoundException; -use Webify\User\Authorization\Domain\Repository\{RoleAssignmentRepositoryInterface, RoleRepositoryInterface}; -use Webify\User\Authorization\Domain\Service\Authorization; -use Webify\User\Authorization\Domain\ValueObject\{Permission, - RoleAssignmentId, - RoleId, - RoleName, - RoleSlug, - SubjectId, - TenantId}; +use Webify\User\Context\Authorization\Domain\Collection\{PermissionCollection, RoleAssignmentCollection}; +use Webify\User\Context\Authorization\Domain\Entity\{Role, RoleAssignment}; +use Webify\User\Context\Authorization\Domain\Exception\RoleNotFoundException; +use Webify\User\Context\Authorization\Domain\Repository\{RoleAssignmentRepositoryInterface, RoleRepositoryInterface}; +use Webify\User\Context\Authorization\Domain\Service\Authorization; +use Webify\User\Context\Authorization\Domain\ValueObject\{Permission, RoleAssignmentId, RoleId, RoleName, RoleSlug, SubjectId, TenantId}; /** * AuthorizationTest tests the functionality of the Authorization service. diff --git a/test/Unit/Authorization/Domain/ValueObject/PermissionTest.php b/test/Unit/Context/Authorization/Domain/ValueObject/PermissionTest.php similarity index 96% rename from test/Unit/Authorization/Domain/ValueObject/PermissionTest.php rename to test/Unit/Context/Authorization/Domain/ValueObject/PermissionTest.php index 92c73c3..8af87a4 100644 --- a/test/Unit/Authorization/Domain/ValueObject/PermissionTest.php +++ b/test/Unit/Context/Authorization/Domain/ValueObject/PermissionTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authorization\Domain\Exception\PermissionValidationException; -use Webify\User\Authorization\Domain\ValueObject\Permission; +use Webify\User\Context\Authorization\Domain\Exception\PermissionValidationException; +use Webify\User\Context\Authorization\Domain\ValueObject\Permission; /** * PermissionTest tests the functionality of the Permission value object. diff --git a/test/Unit/Authorization/Domain/ValueObject/RoleAssignmentIdTest.php b/test/Unit/Context/Authorization/Domain/ValueObject/RoleAssignmentIdTest.php similarity index 92% rename from test/Unit/Authorization/Domain/ValueObject/RoleAssignmentIdTest.php rename to test/Unit/Context/Authorization/Domain/ValueObject/RoleAssignmentIdTest.php index 37156e6..63d7879 100644 --- a/test/Unit/Authorization/Domain/ValueObject/RoleAssignmentIdTest.php +++ b/test/Unit/Context/Authorization/Domain/ValueObject/RoleAssignmentIdTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authorization\Domain\Exception\InvalidRoleAssignmentIdException; -use Webify\User\Authorization\Domain\ValueObject\RoleAssignmentId; +use Webify\User\Context\Authorization\Domain\Exception\InvalidRoleAssignmentIdException; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleAssignmentId; /** * RoleAssignmentIdTest tests the functionality of the RoleAssignmentId value object. diff --git a/test/Unit/Authorization/Domain/ValueObject/RoleIdTest.php b/test/Unit/Context/Authorization/Domain/ValueObject/RoleIdTest.php similarity index 91% rename from test/Unit/Authorization/Domain/ValueObject/RoleIdTest.php rename to test/Unit/Context/Authorization/Domain/ValueObject/RoleIdTest.php index e68e5d8..6002580 100644 --- a/test/Unit/Authorization/Domain/ValueObject/RoleIdTest.php +++ b/test/Unit/Context/Authorization/Domain/ValueObject/RoleIdTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authorization\Domain\Exception\InvalidRoleIdException; -use Webify\User\Authorization\Domain\ValueObject\RoleId; +use Webify\User\Context\Authorization\Domain\Exception\InvalidRoleIdException; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleId; /** * RoleIdTest tests the functionality of the RoleId value object. diff --git a/test/Unit/Authorization/Domain/ValueObject/RoleNameTest.php b/test/Unit/Context/Authorization/Domain/ValueObject/RoleNameTest.php similarity index 90% rename from test/Unit/Authorization/Domain/ValueObject/RoleNameTest.php rename to test/Unit/Context/Authorization/Domain/ValueObject/RoleNameTest.php index b257eeb..9634046 100644 --- a/test/Unit/Authorization/Domain/ValueObject/RoleNameTest.php +++ b/test/Unit/Context/Authorization/Domain/ValueObject/RoleNameTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authorization\Domain\Exception\InvalidRoleNameException; -use Webify\User\Authorization\Domain\ValueObject\RoleName; +use Webify\User\Context\Authorization\Domain\Exception\InvalidRoleNameException; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleName; /** * RoleNameTest tests the functionality of the RoleName value object. diff --git a/test/Unit/Authorization/Domain/ValueObject/RoleSlugTest.php b/test/Unit/Context/Authorization/Domain/ValueObject/RoleSlugTest.php similarity index 96% rename from test/Unit/Authorization/Domain/ValueObject/RoleSlugTest.php rename to test/Unit/Context/Authorization/Domain/ValueObject/RoleSlugTest.php index aadc16d..71df5ae 100644 --- a/test/Unit/Authorization/Domain/ValueObject/RoleSlugTest.php +++ b/test/Unit/Context/Authorization/Domain/ValueObject/RoleSlugTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authorization\Domain\Exception\InvalidRoleSlugException; -use Webify\User\Authorization\Domain\ValueObject\RoleSlug; +use Webify\User\Context\Authorization\Domain\Exception\InvalidRoleSlugException; +use Webify\User\Context\Authorization\Domain\ValueObject\RoleSlug; /** * RoleSlugTest tests the functionality of the RoleSlug value object. diff --git a/test/Unit/Authorization/Domain/ValueObject/SubjectIdTest.php b/test/Unit/Context/Authorization/Domain/ValueObject/SubjectIdTest.php similarity index 92% rename from test/Unit/Authorization/Domain/ValueObject/SubjectIdTest.php rename to test/Unit/Context/Authorization/Domain/ValueObject/SubjectIdTest.php index 6144085..e0d0c0d 100644 --- a/test/Unit/Authorization/Domain/ValueObject/SubjectIdTest.php +++ b/test/Unit/Context/Authorization/Domain/ValueObject/SubjectIdTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authorization\Domain\Exception\InvalidSubjectIdException; -use Webify\User\Authorization\Domain\ValueObject\SubjectId; +use Webify\User\Context\Authorization\Domain\Exception\InvalidSubjectIdException; +use Webify\User\Context\Authorization\Domain\ValueObject\SubjectId; /** * SubjectIdTest tests the functionality of the SubjectId value object. diff --git a/test/Unit/Authorization/Domain/ValueObject/TenantIdTest.php b/test/Unit/Context/Authorization/Domain/ValueObject/TenantIdTest.php similarity index 92% rename from test/Unit/Authorization/Domain/ValueObject/TenantIdTest.php rename to test/Unit/Context/Authorization/Domain/ValueObject/TenantIdTest.php index f556da4..92bd0f4 100644 --- a/test/Unit/Authorization/Domain/ValueObject/TenantIdTest.php +++ b/test/Unit/Context/Authorization/Domain/ValueObject/TenantIdTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Authorization\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Authorization\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Authorization\Domain\Exception\InvalidTenantIdException; -use Webify\User\Authorization\Domain\ValueObject\TenantId; +use Webify\User\Context\Authorization\Domain\Exception\InvalidTenantIdException; +use Webify\User\Context\Authorization\Domain\ValueObject\TenantId; /** * TenantIdTest tests the functionality of the TenantId value object. diff --git a/test/Unit/Identity/Domain/Service/RegisterUserTest.php b/test/Unit/Context/Identity/Application/Service/RegisterUserTest.php similarity index 87% rename from test/Unit/Identity/Domain/Service/RegisterUserTest.php rename to test/Unit/Context/Identity/Application/Service/RegisterUserTest.php index be88f07..64ade97 100644 --- a/test/Unit/Identity/Domain/Service/RegisterUserTest.php +++ b/test/Unit/Context/Identity/Application/Service/RegisterUserTest.php @@ -11,7 +11,7 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\Service; +namespace Webify\User\Test\Unit\Context\Identity\Application\Service; use PHPUnit\Framework\Attributes\{AllowMockObjectsWithoutExpectations, CoversClass, CoversMethod, Test}; use PHPUnit\Framework\MockObject\MockObject; @@ -19,13 +19,13 @@ use Webify\Base\Domain\Contract\Identity\Service\PasswordHasherInterface; use Webify\Base\Domain\Event\DomainEventPublisherInterface; use Webify\Base\Domain\Service\UlidGeneratorInterface; -use Webify\User\Identity\Domain\Entity\User; -use Webify\User\Identity\Domain\Exception\EmailMustBeUniqueException; -use Webify\User\Identity\Domain\Guard\{EmailMustBeUnique, PasswordMustBeStrong}; -use Webify\User\Identity\Domain\Policy\PasswordPolicy; -use Webify\User\Identity\Domain\Repository\UserRepositoryInterface; -use Webify\User\Identity\Domain\Service\RegisterUser; -use Webify\User\Identity\Domain\ValueObject\UserEmail; +use Webify\User\Context\Identity\Application\Service\RegisterUser; +use Webify\User\Context\Identity\Domain\Entity\User; +use Webify\User\Context\Identity\Domain\Exception\EmailMustBeUniqueException; +use Webify\User\Context\Identity\Domain\Guard\{EmailMustBeUnique, PasswordMustBeStrong}; +use Webify\User\Context\Identity\Domain\Policy\PasswordPolicy; +use Webify\User\Context\Identity\Domain\Repository\UserRepositoryInterface; +use Webify\User\Context\Identity\Domain\ValueObject\UserEmail; /** * RegisterUserTest tests the RegisterUser domain service. diff --git a/test/Unit/Identity/Domain/Service/UpdateUserEmailTest.php b/test/Unit/Context/Identity/Application/Service/UpdateUserEmailTest.php similarity index 88% rename from test/Unit/Identity/Domain/Service/UpdateUserEmailTest.php rename to test/Unit/Context/Identity/Application/Service/UpdateUserEmailTest.php index f9c5f43..80ab319 100644 --- a/test/Unit/Identity/Domain/Service/UpdateUserEmailTest.php +++ b/test/Unit/Context/Identity/Application/Service/UpdateUserEmailTest.php @@ -11,19 +11,20 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\Service; +namespace Webify\User\Test\Unit\Context\Identity\Application\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Event\DomainEventPublisherInterface; -use Webify\User\Identity\Domain\Entity\User; -use Webify\User\Identity\Domain\Event\UserEmailWasChanged; -use Webify\User\Identity\Domain\Exception\EmailMustBeUniqueException; -use Webify\User\Identity\Domain\Guard\EmailMustBeUnique; -use Webify\User\Identity\Domain\Repository\UserRepositoryInterface; -use Webify\User\Identity\Domain\Service\UpdateUserEmail; -use Webify\User\Identity\Domain\ValueObject\{DisplayName, PasswordHash, UserEmail, UserId}; +use Webify\User\Context\Identity\Application\Service\UpdateUserEmail; +use Webify\User\Context\Identity\Domain\Entity\User; +use Webify\User\Context\Identity\Domain\Event\UserEmailWasChanged; +use Webify\User\Context\Identity\Domain\Exception\EmailMustBeUniqueException; +use Webify\User\Context\Identity\Domain\Guard\EmailMustBeUnique; +use Webify\User\Context\Identity\Domain\Repository\UserRepositoryInterface; +use Webify\User\Context\Identity\Domain\ValueObject\{DisplayName, UserEmail}; +use Webify\User\Domain\ValueObject\{PasswordHash, UserId}; /** * UpdateUserEmailTest tests the UpdateUserEmail domain service. @@ -184,7 +185,7 @@ private function createUser(string $userId, string $email): User $user = User::register( UserId::fromString($userId), UserEmail::fromString($email), - PasswordHash::fromHash('password_hash'), + PasswordHash::fromHash(password_hash('test_password', PASSWORD_DEFAULT)), DisplayName::fromString('Test User') ); diff --git a/test/Unit/Identity/Domain/Service/UpdateUserPasswordTest.php b/test/Unit/Context/Identity/Application/Service/UpdateUserPasswordTest.php similarity index 85% rename from test/Unit/Identity/Domain/Service/UpdateUserPasswordTest.php rename to test/Unit/Context/Identity/Application/Service/UpdateUserPasswordTest.php index be2eb10..9b6e7cd 100644 --- a/test/Unit/Identity/Domain/Service/UpdateUserPasswordTest.php +++ b/test/Unit/Context/Identity/Application/Service/UpdateUserPasswordTest.php @@ -11,21 +11,22 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\Service; +namespace Webify\User\Test\Unit\Context\Identity\Application\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Webify\Base\Domain\Contract\Identity\Service\PasswordHasherInterface; use Webify\Base\Domain\Event\DomainEventPublisherInterface; -use Webify\User\Identity\Domain\Entity\User; -use Webify\User\Identity\Domain\Event\UserPasswordWasChanged; -use Webify\User\Identity\Domain\Exception\CurrentPasswordNotMatchedException; -use Webify\User\Identity\Domain\Guard\PasswordMustBeStrong; -use Webify\User\Identity\Domain\Policy\PasswordPolicy; -use Webify\User\Identity\Domain\Repository\UserRepositoryInterface; -use Webify\User\Identity\Domain\Service\UpdateUserPassword; -use Webify\User\Identity\Domain\ValueObject\{DisplayName, PasswordHash, UserEmail, UserId}; +use Webify\User\Context\Identity\Application\Service\UpdateUserPassword; +use Webify\User\Context\Identity\Domain\Entity\User; +use Webify\User\Context\Identity\Domain\Event\UserPasswordWasChanged; +use Webify\User\Context\Identity\Domain\Exception\CurrentPasswordNotMatchedException; +use Webify\User\Context\Identity\Domain\Guard\PasswordMustBeStrong; +use Webify\User\Context\Identity\Domain\Policy\PasswordPolicy; +use Webify\User\Context\Identity\Domain\Repository\UserRepositoryInterface; +use Webify\User\Context\Identity\Domain\ValueObject\{DisplayName, UserEmail}; +use Webify\User\Domain\ValueObject\{PasswordHash, UserId}; /** * UpdateUserPasswordTest tests the UpdateUserPassword domain service. @@ -97,8 +98,8 @@ public function testUpdateUserPasswordSuccessfully(): void $userId = '01ARZ3NDEKTSV4RRFFQ69G5FAV'; $currentPassword = 'current_password'; $newPassword = 'new_password'; - $currentPasswordHash = 'current_password_hash'; - $newPasswordHash = 'new_password_hash'; + $currentPasswordHash = password_hash('current_password', PASSWORD_DEFAULT); + $newPasswordHash = password_hash('new_password', PASSWORD_DEFAULT); $user = $this->createUser($userId, $currentPasswordHash); $this->repository @@ -154,7 +155,7 @@ public function testUpdateThrowsExceptionWhenCurrentPasswordIsInvalid(): void { $userId = '01ARZ3NDEKTSV4RRFFQ69G5FAV'; $currentPassword = 'wrong_current_password'; - $currentPasswordHash = 'current_password_hash'; + $currentPasswordHash = password_hash('current_password', PASSWORD_DEFAULT); $user = $this->createUser($userId, $currentPasswordHash); $this->repository diff --git a/test/Unit/Identity/Domain/Entity/UserTest.php b/test/Unit/Context/Identity/Domain/Entity/UserTest.php similarity index 88% rename from test/Unit/Identity/Domain/Entity/UserTest.php rename to test/Unit/Context/Identity/Domain/Entity/UserTest.php index c94fa56..aeb17df 100644 --- a/test/Unit/Identity/Domain/Entity/UserTest.php +++ b/test/Unit/Context/Identity/Domain/Entity/UserTest.php @@ -11,22 +11,16 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\Entity; +namespace Webify\User\Test\Unit\Context\Identity\Domain\Entity; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Identity\Domain\Entity\User; -use Webify\User\Identity\Domain\Event\{UserDisplayNameWasChanged, - UserEmailWasChanged, - UserPasswordWasChanged, - UserWasActivated, - UserWasDeactivated, - UserWasRegistered}; -use Webify\User\Identity\Domain\Exception\{UserAlreadyActivatedException, - UserAlreadyDeactivatedException, - UserCannotBeDeactivatedException}; -use Webify\User\Identity\Domain\ValueObject\{DisplayName, PasswordHash, UserEmail, UserId}; -use Webify\User\Identity\Infrastructure\Service\PasswordHasher; +use Webify\User\Context\Identity\Domain\Entity\User; +use Webify\User\Context\Identity\Domain\Event\{UserDisplayNameWasChanged, UserEmailWasChanged, UserPasswordWasChanged, UserWasActivated, UserWasDeactivated, UserWasRegistered}; +use Webify\User\Context\Identity\Domain\Exception\{UserAlreadyActivatedException, UserAlreadyDeactivatedException, UserCannotBeDeactivatedException}; +use Webify\User\Context\Identity\Domain\ValueObject\{DisplayName, UserEmail}; +use Webify\User\Context\Identity\Infrastructure\Service\PasswordHasher; +use Webify\User\Domain\ValueObject\{PasswordHash, UserId}; /** * UserTest tests the functionality of the User entity. diff --git a/test/Unit/Identity/Domain/Guard/EmailMustBeUniqueTest.php b/test/Unit/Context/Identity/Domain/Guard/EmailMustBeUniqueTest.php similarity index 83% rename from test/Unit/Identity/Domain/Guard/EmailMustBeUniqueTest.php rename to test/Unit/Context/Identity/Domain/Guard/EmailMustBeUniqueTest.php index 5da4f07..cd80f19 100644 --- a/test/Unit/Identity/Domain/Guard/EmailMustBeUniqueTest.php +++ b/test/Unit/Context/Identity/Domain/Guard/EmailMustBeUniqueTest.php @@ -11,14 +11,14 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\Guard; +namespace Webify\User\Test\Unit\Context\Identity\Domain\Guard; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Identity\Domain\Exception\EmailMustBeUniqueException; -use Webify\User\Identity\Domain\Guard\EmailMustBeUnique; -use Webify\User\Identity\Domain\Repository\UserRepositoryInterface; -use Webify\User\Identity\Domain\ValueObject\UserEmail; +use Webify\User\Context\Identity\Domain\Exception\EmailMustBeUniqueException; +use Webify\User\Context\Identity\Domain\Guard\EmailMustBeUnique; +use Webify\User\Context\Identity\Domain\Repository\UserRepositoryInterface; +use Webify\User\Context\Identity\Domain\ValueObject\UserEmail; /** * EmailMustBeUniqueTest tests the functionality of the EmailMustBeUnique guard. diff --git a/test/Unit/Identity/Domain/Guard/PasswordMustBeStrongTest.php b/test/Unit/Context/Identity/Domain/Guard/PasswordMustBeStrongTest.php similarity index 91% rename from test/Unit/Identity/Domain/Guard/PasswordMustBeStrongTest.php rename to test/Unit/Context/Identity/Domain/Guard/PasswordMustBeStrongTest.php index 065c0a1..2287bde 100644 --- a/test/Unit/Identity/Domain/Guard/PasswordMustBeStrongTest.php +++ b/test/Unit/Context/Identity/Domain/Guard/PasswordMustBeStrongTest.php @@ -11,13 +11,13 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\Guard; +namespace Webify\User\Test\Unit\Context\Identity\Domain\Guard; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Identity\Domain\Exception\WeakPasswordException; -use Webify\User\Identity\Domain\Guard\PasswordMustBeStrong; -use Webify\User\Identity\Domain\Policy\PasswordPolicy; +use Webify\User\Context\Identity\Domain\Exception\WeakPasswordException; +use Webify\User\Context\Identity\Domain\Guard\PasswordMustBeStrong; +use Webify\User\Context\Identity\Domain\Policy\PasswordPolicy; /** * PasswordMustBeStrongTest tests the PasswordMustBeStrong guard. diff --git a/test/Unit/Identity/Domain/ValueObject/DisplayNameTest.php b/test/Unit/Context/Identity/Domain/ValueObject/DisplayNameTest.php similarity index 94% rename from test/Unit/Identity/Domain/ValueObject/DisplayNameTest.php rename to test/Unit/Context/Identity/Domain/ValueObject/DisplayNameTest.php index 7b853bc..3f496d9 100644 --- a/test/Unit/Identity/Domain/ValueObject/DisplayNameTest.php +++ b/test/Unit/Context/Identity/Domain/ValueObject/DisplayNameTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Identity\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Identity\Domain\Exception\InvalidDisplayNameException; -use Webify\User\Identity\Domain\ValueObject\DisplayName; +use Webify\User\Context\Identity\Domain\Exception\InvalidDisplayNameException; +use Webify\User\Context\Identity\Domain\ValueObject\DisplayName; /** * DisplayNameTest tests the functionality of the DisplayName value object. diff --git a/test/Unit/Identity/Domain/ValueObject/UserEmailTest.php b/test/Unit/Context/Identity/Domain/ValueObject/UserEmailTest.php similarity index 84% rename from test/Unit/Identity/Domain/ValueObject/UserEmailTest.php rename to test/Unit/Context/Identity/Domain/ValueObject/UserEmailTest.php index 9820f20..18b56bb 100644 --- a/test/Unit/Identity/Domain/ValueObject/UserEmailTest.php +++ b/test/Unit/Context/Identity/Domain/ValueObject/UserEmailTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\ValueObject; +namespace Webify\User\Test\Unit\Context\Identity\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Identity\Domain\Exception\InvalidUserEmailException; -use Webify\User\Identity\Domain\ValueObject\UserEmail; +use Webify\User\Context\Identity\Domain\Exception\InvalidUserEmailException; +use Webify\User\Context\Identity\Domain\ValueObject\UserEmail; /** * UserEmailTest tests the functionality of the UserEmail value object. diff --git a/test/Unit/Identity/Domain/Service/PasswordHasherTest.php b/test/Unit/Context/Identity/Infrastructure/Service/PasswordHasherTest.php similarity index 95% rename from test/Unit/Identity/Domain/Service/PasswordHasherTest.php rename to test/Unit/Context/Identity/Infrastructure/Service/PasswordHasherTest.php index 591f7e6..4b161f7 100644 --- a/test/Unit/Identity/Domain/Service/PasswordHasherTest.php +++ b/test/Unit/Context/Identity/Infrastructure/Service/PasswordHasherTest.php @@ -11,11 +11,11 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\Service; +namespace Webify\User\Test\Unit\Context\Identity\Infrastructure\Service; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Identity\Infrastructure\Service\PasswordHasher; +use Webify\User\Context\Identity\Infrastructure\Service\PasswordHasher; /** * PasswordHashTest tests the functionality of the PasswordHash service. diff --git a/test/Unit/Identity/Domain/ValueObject/PasswordHashTest.php b/test/Unit/Domain/ValueObject/PasswordHashTest.php similarity index 55% rename from test/Unit/Identity/Domain/ValueObject/PasswordHashTest.php rename to test/Unit/Domain/ValueObject/PasswordHashTest.php index 977c8c0..8cb4deb 100644 --- a/test/Unit/Identity/Domain/ValueObject/PasswordHashTest.php +++ b/test/Unit/Domain/ValueObject/PasswordHashTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\ValueObject; +namespace Webify\User\Test\Unit\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Identity\Domain\Exception\InvalidPasswordHashException; -use Webify\User\Identity\Domain\ValueObject\PasswordHash; +use Webify\User\Domain\Exception\InvalidPasswordHashException; +use Webify\User\Domain\ValueObject\PasswordHash; /** * PasswordHashTest tests the functionality of the HashedPassword value object. @@ -78,9 +78,63 @@ public function testEqualsReturnsTrueForSameHash(): void #[Test] public function testEqualsReturnsFalseForDifferentHash(): void { - $hashedPassword1 = PasswordHash::fromHash('hash1'); - $hashedPassword2 = PasswordHash::fromHash('hash2'); + $hashedPassword1 = PasswordHash::fromHash(password_hash('password_one', PASSWORD_DEFAULT)); + $hashedPassword2 = PasswordHash::fromHash(password_hash('password_two', PASSWORD_DEFAULT)); $this->assertFalse($hashedPassword1->equals($hashedPassword2)); } + + #[Test] + public function testPlaintextPasswordIsRejected(): void + { + $this->expectException(InvalidPasswordHashException::class); + PasswordHash::fromHash('test_password'); + } + + #[Test] + public function testMalformedHashIsRejected(): void + { + $this->expectException(InvalidPasswordHashException::class); + PasswordHash::fromHash('not-a-hash'); + } + + #[Test] + public function testZeroStringIsRejected(): void + { + $this->expectException(InvalidPasswordHashException::class); + PasswordHash::fromHash('0'); + } + + #[Test] + public function testWhitespaceOnlyValueIsRejected(): void + { + $this->expectException(InvalidPasswordHashException::class); + PasswordHash::fromHash(' '); + } + + #[Test] + public function testPaddedHashIsRejectedRatherThanSilentlyTrimmed(): void + { + $padded = ' ' . password_hash('test_password', PASSWORD_DEFAULT) . ' '; + + $this->expectException(InvalidPasswordHashException::class); + PasswordHash::fromHash($padded); + } + + #[Test] + public function testTruncatedHashIsRejected(): void + { + $hash = password_hash('test_password', PASSWORD_DEFAULT); + + $this->expectException(InvalidPasswordHashException::class); + PasswordHash::fromHash(substr($hash, 0, 20)); + } + + #[Test] + public function testHashFromNonDefaultAlgorithmIsAccepted(): void + { + $hash = password_hash('test_password', PASSWORD_ARGON2ID); + + $this->assertSame($hash, PasswordHash::fromHash($hash)->toNative()); + } } diff --git a/test/Unit/Identity/Domain/ValueObject/UserIdTest.php b/test/Unit/Domain/ValueObject/UserIdTest.php similarity index 86% rename from test/Unit/Identity/Domain/ValueObject/UserIdTest.php rename to test/Unit/Domain/ValueObject/UserIdTest.php index 435d06d..ad8c0f2 100644 --- a/test/Unit/Identity/Domain/ValueObject/UserIdTest.php +++ b/test/Unit/Domain/ValueObject/UserIdTest.php @@ -11,12 +11,12 @@ */ declare(strict_types=1); -namespace Webify\User\Test\Unit\Identity\Domain\ValueObject; +namespace Webify\User\Test\Unit\Domain\ValueObject; use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; use PHPUnit\Framework\TestCase; -use Webify\User\Identity\Domain\Exception\InvalidUserIdException; -use Webify\User\Identity\Domain\ValueObject\UserId; +use Webify\User\Domain\Exception\InvalidUserIdException; +use Webify\User\Domain\ValueObject\UserId; /** * UserIdTest tests the functionality of the UserId value object. diff --git a/test/Unit/Domain/ValueObject/UserStatusTest.php b/test/Unit/Domain/ValueObject/UserStatusTest.php new file mode 100644 index 0000000..2cb7ec9 --- /dev/null +++ b/test/Unit/Domain/ValueObject/UserStatusTest.php @@ -0,0 +1,185 @@ + + */ +declare(strict_types=1); + +namespace Webify\User\Test\Unit\Domain\ValueObject; + +use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; +use PHPUnit\Framework\TestCase; +use ValueError; +use Webify\User\Domain\ValueObject\UserStatus; + +/** + * UserStatusTest tests the functionality of the UserStatus value object. + * + * @internal + */ +#[CoversClass(UserStatus::class)] +#[CoversMethod(UserStatus::class, 'fromString')] +#[CoversMethod(UserStatus::class, 'isActive')] +#[CoversMethod(UserStatus::class, 'isInactive')] +#[CoversMethod(UserStatus::class, 'isDeactivated')] +#[CoversMethod(UserStatus::class, 'isUnverified')] +final class UserStatusTest extends TestCase +{ + /** + * Tests whether the `UserStatus::Active` status is correctly identified as active. + */ + #[Test] + public function testActiveStatusIsActive(): void + { + $status = UserStatus::Active; + + $this->assertTrue($status->isActive()); + $this->assertFalse($status->isInactive()); + $this->assertFalse($status->isDeactivated()); + $this->assertFalse($status->isUnverified()); + } + + /** + * Tests whether the `UserStatus::Inactive` status is correctly identified as inactive. + */ + #[Test] + public function testInactiveStatusIsInactive(): void + { + $status = UserStatus::Inactive; + + $this->assertFalse($status->isActive()); + $this->assertTrue($status->isInactive()); + $this->assertFalse($status->isDeactivated()); + $this->assertFalse($status->isUnverified()); + } + + /** + * Tests whether the `UserStatus::Deactivated` status is correctly identified as deactivated. + */ + #[Test] + public function testDeactivatedStatusIsDeactivated(): void + { + $status = UserStatus::Deactivated; + + $this->assertFalse($status->isActive()); + $this->assertFalse($status->isInactive()); + $this->assertTrue($status->isDeactivated()); + $this->assertFalse($status->isUnverified()); + } + + /** + * Tests whether the `UserStatus::Unverified` status is correctly identified as unverified. + * + * This case was contributed by Authentication when the enum was merged into the shared + * kernel, where Identity's three lifecycle cases used to be the only ones. + */ + #[Test] + public function testUnverifiedStatusIsUnverified(): void + { + $status = UserStatus::Unverified; + + $this->assertFalse($status->isActive()); + $this->assertFalse($status->isInactive()); + $this->assertFalse($status->isDeactivated()); + $this->assertTrue($status->isUnverified()); + } + + /** + * Tests that each status reports only its own case. + */ + #[Test] + public function testEveryCaseReportsOnlyItself(): void + { + foreach (UserStatus::cases() as $status) { + foreach (UserStatus::cases() as $other) { + $this->assertSame( + $status === $other, + $status->{'is' . $other->name}(), + sprintf('%s::is%s() should be %s', $status->name, $other->name, $status === $other ? 'true' : 'false') + ); + } + } + } + + /** + * Tests status values. + */ + #[Test] + public function testStatusValues(): void + { + $this->assertSame('active', UserStatus::Active->value); + $this->assertSame('inactive', UserStatus::Inactive->value); + $this->assertSame('deactivated', UserStatus::Deactivated->value); + $this->assertSame('unverified', UserStatus::Unverified->value); + } + + /** + * Tests weather can create status from value. + */ + #[Test] + public function testStatusFromValue(): void + { + $this->assertSame(UserStatus::Active, UserStatus::from('active')); + $this->assertSame(UserStatus::Inactive, UserStatus::from('inactive')); + $this->assertSame(UserStatus::Deactivated, UserStatus::from('deactivated')); + $this->assertSame(UserStatus::Unverified, UserStatus::from('unverified')); + } + + /** + * Tests throwing exception for invalid value. + */ + #[Test] + public function testInvalidValueThrowsException(): void + { + $this->expectException(ValueError::class); + UserStatus::from('invalid'); + } + + /** + * Tests every case survives the round trip through its stored string. + * + * Identity's lifecycle cases must not collapse on the way in, otherwise a deactivated + * user is reported to guards as unverified and rejected for the wrong reason. + */ + #[Test] + public function testFromStringResolvesEveryCaseToItself(): void + { + foreach (UserStatus::cases() as $status) { + $this->assertSame( + $status, + UserStatus::fromString($status->value), + sprintf('status "%s" must resolve to its own case', $status->value) + ); + } + } + + /** + * Tests an unreadable status fails closed instead of throwing. + * + * `from()` would raise a ValueError here, escaping whatever flow happened to read the + * row. `fromString()` reports `Unverified` so a guard rejects the user deliberately. + */ + #[Test] + public function testFromStringFallsBackToUnverifiedForUnknownValue(): void + { + $this->assertSame(UserStatus::Unverified, UserStatus::fromString('unknown_status')); + $this->assertFalse(UserStatus::fromString('unknown_status')->isActive()); + } + + /** + * Tests the fallback also covers values that are empty or the wrong shape entirely. + */ + #[Test] + public function testFromStringFallsBackToUnverifiedForUnusableValue(): void + { + $this->assertSame(UserStatus::Unverified, UserStatus::fromString('')); + $this->assertSame(UserStatus::Unverified, UserStatus::fromString('0')); + $this->assertSame(UserStatus::Unverified, UserStatus::fromString('Active')); + } +} diff --git a/test/Unit/Identity/Domain/ValueObject/UserStatusTest.php b/test/Unit/Identity/Domain/ValueObject/UserStatusTest.php deleted file mode 100644 index 2d03d97..0000000 --- a/test/Unit/Identity/Domain/ValueObject/UserStatusTest.php +++ /dev/null @@ -1,102 +0,0 @@ - - */ -declare(strict_types=1); - -namespace Webify\User\Test\Unit\Identity\Domain\ValueObject; - -use PHPUnit\Framework\Attributes\{CoversClass, CoversMethod, Test}; -use PHPUnit\Framework\TestCase; -use ValueError; -use Webify\User\Identity\Domain\ValueObject\UserStatus; - -/** - * UserStatusTest tests the functionality of the UserStatus value object. - * - * @internal - */ -#[CoversClass(UserStatus::class)] -#[CoversMethod(UserStatus::class, 'isActive')] -#[CoversMethod(UserStatus::class, 'isInactive')] -#[CoversMethod(UserStatus::class, 'isDeactivated')] -final class UserStatusTest extends TestCase -{ - /** - * Tests whether the `UserStatus::Active` status is correctly identified as active. - */ - #[Test] - public function testActiveStatusIsActive(): void - { - $status = UserStatus::Active; - - $this->assertTrue($status->isActive()); - $this->assertFalse($status->isInactive()); - $this->assertFalse($status->isDeactivated()); - } - - /** - * Tests whether the `UserStatus::Inactive` status is correctly identified as inactive. - */ - #[Test] - public function testInactiveStatusIsInactive(): void - { - $status = UserStatus::Inactive; - - $this->assertFalse($status->isActive()); - $this->assertTrue($status->isInactive()); - $this->assertFalse($status->isDeactivated()); - } - - /** - * Tests whether the `UserStatus::Deactivated` status is correctly identified as deactivated. - */ - #[Test] - public function testDeactivatedStatusIsDeactivated(): void - { - $status = UserStatus::Deactivated; - - $this->assertFalse($status->isActive()); - $this->assertFalse($status->isInactive()); - $this->assertTrue($status->isDeactivated()); - } - - /** - * Tests status values. - */ - #[Test] - public function testStatusValues(): void - { - $this->assertSame('active', UserStatus::Active->value); - $this->assertSame('inactive', UserStatus::Inactive->value); - $this->assertSame('deactivated', UserStatus::Deactivated->value); - } - - /** - * Tests weather can create status from value. - */ - #[Test] - public function testStatusFromValue(): void - { - $this->assertSame(UserStatus::Active, UserStatus::from('active')); - $this->assertSame(UserStatus::Inactive, UserStatus::from('inactive')); - $this->assertSame(UserStatus::Deactivated, UserStatus::from('deactivated')); - } - - /** - * Tests throwing exception for invalid value. - */ - #[Test] - public function testInvalidValueThrowsException(): void - { - $this->expectException(ValueError::class); - UserStatus::from('invalid'); - } -} diff --git a/test/Unit/Infrastructure/Extension/UserExtensionTest.php b/test/Unit/Infrastructure/Extension/UserExtensionTest.php new file mode 100644 index 0000000..2c7ddcb --- /dev/null +++ b/test/Unit/Infrastructure/Extension/UserExtensionTest.php @@ -0,0 +1,201 @@ + + */ +declare(strict_types=1); + +namespace Webify\User\Test\Unit\Infrastructure\Extension; + +use PHPUnit\Framework\Attributes\{CoversClass, CoversFunction, CoversMethod, Test}; +use PHPUnit\Framework\TestCase; +use Webify\Base\Infrastructure\Contract\{ExtensionInterface, ServiceProviderInterface}; +use Webify\User\Infrastructure\Extension\UserExtension; +use Webify\User\Infrastructure\Provider\UserService; + +use function dirname; + +/** + * UserExtensionTest tests the extension entry point metadata. + * + * @internal + */ +#[CoversClass(UserExtension::class)] +#[CoversFunction('dirname')] +#[CoversMethod(UserExtension::class, 'getId')] +#[CoversMethod(UserExtension::class, 'getSlug')] +#[CoversMethod(UserExtension::class, 'getName')] +#[CoversMethod(UserExtension::class, 'getVersion')] +#[CoversMethod(UserExtension::class, 'getTemplatePath')] +#[CoversMethod(UserExtension::class, 'getProviders')] +#[CoversMethod(UserExtension::class, 'getAssetsProvider')] +final class UserExtensionTest extends TestCase +{ + /** + * @var UserExtension the user extension instance + */ + private UserExtension $extension; + + /** + * {@inheritdoc} + */ + protected function setUp(): void + { + $this->extension = new UserExtension(); + } + + /** + * The extension must satisfy the ext-base contract it is discovered through. + */ + #[Test] + public function testImplementsExtensionInterface(): void + { + $this->assertInstanceOf(ExtensionInterface::class, $this->extension); + } + + /** + * The id is the stable key the kernel discovers extensions by and resolves templates + * through, so it must not drift once anything depends on it. + * + * @see ExtensionInterface::getId() + */ + #[Test] + public function testGetId(): void + { + $this->assertSame('webifycms-user', $this->extension->getId()); + } + + /** + * The slug is a URL-facing label rather than an identity, so it only mirrors the id here + * — nothing in ext-base keys a lookup off it. + * + * @see ExtensionInterface::getSlug() + */ + #[Test] + public function testGetSlug(): void + { + $this->assertSame('webifycms-user', $this->extension->getSlug()); + } + + /** + * The display name is what a human reads in the admin, so it carries the package's full + * title rather than its machine name. + * + * @see ExtensionInterface::getName() + */ + #[Test] + public function testGetName(): void + { + $this->assertSame('WebifyCMS User Extension', $this->extension->getName()); + } + + /** + * The version is a hand-maintained release marker, not a value derived from composer.json, + * so a release has to bump both in the same change. + * + * @see ExtensionInterface::getVersion() + */ + #[Test] + public function testGetVersion(): void + { + $this->assertSame('0.2.0-beta', $this->extension->getVersion()); + } + + /** + * The extension lives in `src/Infrastructure/Extension`, so its root is three levels up + * and the templates directory sits beside `src`. + * + * @see ExtensionInterface::getTemplatePath() + */ + #[Test] + public function testGetTemplatePathPointsAtThePackageTemplatesDirectory(): void + { + $path = $this->extension->getTemplatePath()->toNative(); + $packageRoot = dirname(__DIR__, 4); + + $this->assertSame( + $packageRoot . DIRECTORY_SEPARATOR . 'templates', + $path, + 'the template path must resolve to /templates' + ); + $this->assertDirectoryExists($path); + } + + /** + * The three contexts each contribute definitions, so the extension yields the one + * provider that gathers them. + * + * @see ExtensionInterface::getProviders() + */ + #[Test] + public function testGetProvidersYieldsTheContextProvider(): void + { + $providers = $this->extension->getProviders(); + + $this->assertCount(1, $providers); + $this->assertInstanceOf(UserService::class, $providers[0]); + } + + /** + * Whatever is returned must be usable by the container, so guard the shape of the list. + * + * The contract admits either provider interface, and the container builder only + * registers definitions from the plain service provider — so that is the one the + * list is asserted against. + * + * @see ExtensionInterface::getProviders() + */ + #[Test] + public function testGetProvidersOnlyYieldsServiceProviderInstances(): void + { + $this->assertContainsOnlyInstancesOf( + ServiceProviderInterface::class, + $this->extension->getProviders() + ); + } + + /** + * The provider's definitions are what the container actually receives, so a + * provider that returned nothing would pass every test above while registering + * no definitions at all. + * + * Mirrors how the container builder consumes the list: only the plain service + * provider carries definitions, and a bootstrap provider is registered for its + * side effects instead. + * + * @see ExtensionInterface::getProviders() + */ + #[Test] + public function testTheProvidersContributeDefinitions(): void + { + $definitions = []; + + foreach ($this->extension->getProviders() as $provider) { + if (!$provider instanceof ServiceProviderInterface) { + continue; + } + + $definitions += $provider->getDefinitions(); + } + + $this->assertNotEmpty($definitions); + } + + /** + * The extension ships no assets of its own — front-end assets come from the theme — so + * the contract's "nothing to publish" case is the correct answer here. + * + * @see ExtensionInterface::getAssetsProvider() + */ + #[Test] + public function testGetAssetsProviderIsNull(): void + { + $this->assertNull($this->extension->getAssetsProvider()); + } +}