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 @@
[](https://www.php.net)
[](LICENSE.md)
-[](https://github.com/webifycms/ext-base)
[]()
> 👋 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());
+ }
+}